1 /* $NetBSD: rtc.c,v 1.25 2008/01/04 22:13:57 ad Exp $ */
4 * Copyright (c) 1999 Shin Takemura. All rights reserved.
5 * Copyright (c) 1999 SATO Kazumi. All rights reserved.
6 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the PocketBSD project
19 * and its contributors.
20 * 4. Neither the name of the project nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: rtc.c,v 1.25 2008/01/04 22:13:57 ad Exp $");
41 #include "opt_vr41xx.h"
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/timetc.h>
46 #include <sys/device.h>
48 #include <machine/sysconf.h>
49 #include <machine/bus.h>
51 #include <dev/clock_subr.h>
53 #include <hpcmips/vr/vr.h>
54 #include <hpcmips/vr/vrcpudef.h>
55 #include <hpcmips/vr/vripif.h>
56 #include <hpcmips/vr/vripreg.h>
57 #include <hpcmips/vr/rtcreg.h>
60 * for debugging definitions
61 * VRRTCDEBUG print rtc debugging information
64 #ifndef VRRTCDEBUG_CONF
65 #define VRRTCDEBUG_CONF 0
67 int vrrtc_debug
= VRRTCDEBUG_CONF
;
68 #define DPRINTF(arg) if (vrrtc_debug) printf arg;
69 #define DDUMP_REGS(arg) if (vrrtc_debug) vrrtc_dump_regs(arg);
70 #else /* VRRTCDEBUG */
72 #define DDUMP_REGS(arg)
73 #endif /* VRRTCDEBUG */
77 bus_space_tag_t sc_iot
;
78 bus_space_handle_t sc_ioh
;
80 #ifndef SINGLE_VRIP_BASE
82 int sc_tclk_h_reg
, sc_tclk_l_reg
;
83 int sc_tclk_cnt_h_reg
, sc_tclk_cnt_l_reg
;
84 #endif /* SINGLE_VRIP_BASE */
86 struct todr_chip_handle sc_todr
;
87 struct timecounter sc_tc
;
90 void vrrtc_init(struct device
*);
91 int vrrtc_get(todr_chip_handle_t
, struct timeval
*);
92 int vrrtc_set(todr_chip_handle_t
, struct timeval
*);
93 uint32_t vrrtc_get_timecount(struct timecounter
*);
95 struct platform_clock vr_clock
= {
96 #define CLOCK_RATE 128
97 CLOCK_RATE
, vrrtc_init
,
100 int vrrtc_match(struct device
*, struct cfdata
*, void *);
101 void vrrtc_attach(struct device
*, struct device
*, void *);
102 int vrrtc_intr(void*, u_int32_t
, u_int32_t
);
103 void vrrtc_dump_regs(struct vrrtc_softc
*);
105 CFATTACH_DECL(vrrtc
, sizeof(struct vrrtc_softc
),
106 vrrtc_match
, vrrtc_attach
, NULL
, NULL
);
109 vrrtc_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
115 #ifndef SINGLE_VRIP_BASE
116 #define RTCINT_REG_W (sc->sc_rtcint_reg)
117 #define TCLK_H_REG_W (sc->sc_tclk_h_reg)
118 #define TCLK_L_REG_W (sc->sc_tclk_l_reg)
119 #define TCLK_CNT_H_REG_W (sc->sc_tclk_cnt_h_reg)
120 #define TCLK_CNT_L_REG_W (sc->sc_tclk_cnt_l_reg)
121 #endif /* SINGLE_VRIP_BASE */
124 vrrtc_attach(struct device
*parent
, struct device
*self
, void *aux
)
126 struct vrip_attach_args
*va
= aux
;
127 struct vrrtc_softc
*sc
= (void *)self
;
130 #ifndef SINGLE_VRIP_BASE
131 if (va
->va_addr
== VR4102_RTC_ADDR
) {
132 sc
->sc_rtcint_reg
= VR4102_RTCINT_REG_W
;
133 sc
->sc_tclk_h_reg
= VR4102_TCLK_H_REG_W
;
134 sc
->sc_tclk_l_reg
= VR4102_TCLK_L_REG_W
;
135 sc
->sc_tclk_cnt_h_reg
= VR4102_TCLK_CNT_H_REG_W
;
136 sc
->sc_tclk_cnt_l_reg
= VR4102_TCLK_CNT_L_REG_W
;
138 if (va
->va_addr
== VR4122_RTC_ADDR
) {
139 sc
->sc_rtcint_reg
= VR4122_RTCINT_REG_W
;
140 sc
->sc_tclk_h_reg
= VR4122_TCLK_H_REG_W
;
141 sc
->sc_tclk_l_reg
= VR4122_TCLK_L_REG_W
;
142 sc
->sc_tclk_cnt_h_reg
= VR4122_TCLK_CNT_H_REG_W
;
143 sc
->sc_tclk_cnt_l_reg
= VR4122_TCLK_CNT_L_REG_W
;
145 if (va
->va_addr
== VR4181_RTC_ADDR
) {
146 sc
->sc_rtcint_reg
= VR4181_RTCINT_REG_W
;
147 sc
->sc_tclk_h_reg
= RTC_NO_REG_W
;
148 sc
->sc_tclk_l_reg
= RTC_NO_REG_W
;
149 sc
->sc_tclk_cnt_h_reg
= RTC_NO_REG_W
;
150 sc
->sc_tclk_cnt_l_reg
= RTC_NO_REG_W
;
152 panic("%s: unknown base address 0x%lx",
153 sc
->sc_dev
.dv_xname
, va
->va_addr
);
155 #endif /* SINGLE_VRIP_BASE */
157 sc
->sc_iot
= va
->va_iot
;
158 if (bus_space_map(sc
->sc_iot
, va
->va_addr
, va
->va_size
,
159 0 /* no flags */, &sc
->sc_ioh
)) {
160 printf("vrrtc_attach: can't map i/o space\n");
163 /* RTC interrupt handler is directly dispatched from CPU intr */
164 vr_intr_establish(VR_INTR1
, vrrtc_intr
, sc
);
165 /* But need to set level 1 interrupt mask register,
166 * so regsiter fake interrurpt handler
168 if (!(sc
->sc_ih
= vrip_intr_establish(va
->va_vc
, va
->va_unit
, 0,
170 printf (":can't map interrupt.\n");
174 * Rtc is attached to call this routine
175 * before cpu_initclock() calls clock_init().
176 * So we must disable all interrupt for now.
179 * Disable all rtc interrupts
181 /* Disable Elapse compare intr */
182 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_H_REG_W
, 0);
183 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_M_REG_W
, 0);
184 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_L_REG_W
, 0);
185 /* Disable RTC Long1 intr */
186 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_H_REG_W
, 0);
187 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_L_REG_W
, 0);
188 /* Disable RTC Long2 intr */
189 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_H_REG_W
, 0);
190 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_L_REG_W
, 0);
191 /* Disable RTC TCLK intr */
192 if (TCLK_H_REG_W
!= RTC_NO_REG_W
) {
193 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_H_REG_W
, 0);
194 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_L_REG_W
, 0);
197 * Clear all rtc intrrupts.
199 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCINT_REG_W
, RTCINT_ALL
);
202 * Figure out the epoch, which could be either forward or
203 * backwards in time. We assume that the start date will always
206 for (year
= EPOCHYEAR
; year
< POSIX_BASE_YEAR
; year
++) {
207 sc
->sc_epoch
+= LEAPYEAR4(year
) ? SECYR
+ SECDAY
: SECYR
;
209 for (year
= POSIX_BASE_YEAR
; year
< EPOCHYEAR
; year
++) {
210 sc
->sc_epoch
-= LEAPYEAR4(year
) ? SECYR
+ SECDAY
: SECYR
;
214 * Initialize MI todr(9)
216 sc
->sc_todr
.todr_settime
= vrrtc_set
;
217 sc
->sc_todr
.todr_gettime
= vrrtc_get
;
218 sc
->sc_todr
.cookie
= sc
;
219 todr_attach(&sc
->sc_todr
);
221 platform_clock_attach(sc
, &vr_clock
);
225 vrrtc_intr(void *arg
, u_int32_t pc
, u_int32_t statusReg
)
227 struct vrrtc_softc
*sc
= arg
;
228 struct clockframe cf
;
230 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCINT_REG_W
, RTCINT_ALL
);
239 vrrtc_init(struct device
*dev
)
241 struct vrrtc_softc
*sc
= (struct vrrtc_softc
*)dev
;
245 * Set tick (CLOCK_RATE)
247 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_H_REG_W
, 0);
248 bus_space_write_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_L_REG_W
,
249 RTCL1_L_HZ
/CLOCK_RATE
);
252 * Initialize timecounter.
254 sc
->sc_tc
.tc_get_timecount
= vrrtc_get_timecount
;
255 sc
->sc_tc
.tc_name
= "vrrtc";
256 sc
->sc_tc
.tc_counter_mask
= 0xffff;
257 sc
->sc_tc
.tc_frequency
= ETIME_L_HZ
;
258 sc
->sc_tc
.tc_priv
= sc
;
259 sc
->sc_tc
.tc_quality
= 100;
264 vrrtc_get_timecount(struct timecounter
*tc
)
266 struct vrrtc_softc
*sc
= (struct vrrtc_softc
*)tc
->tc_priv
;
267 bus_space_tag_t iot
= sc
->sc_iot
;
268 bus_space_handle_t ioh
= sc
->sc_ioh
;
270 return (bus_space_read_2(iot
, ioh
, ETIME_L_REG_W
));
274 vrrtc_get(todr_chip_handle_t tch
, struct timeval
*tvp
)
277 struct vrrtc_softc
*sc
= (struct vrrtc_softc
*)tch
->cookie
;
278 bus_space_tag_t iot
= sc
->sc_iot
;
279 bus_space_handle_t ioh
= sc
->sc_ioh
;
280 u_int32_t timeh
; /* elapse time (2*timeh sec) */
281 u_int32_t timel
; /* timel/32768 sec */
284 timeh
= bus_space_read_2(iot
, ioh
, ETIME_H_REG_W
);
285 timeh
= (timeh
<< 16) | bus_space_read_2(iot
, ioh
, ETIME_M_REG_W
);
286 timel
= bus_space_read_2(iot
, ioh
, ETIME_L_REG_W
);
288 DPRINTF(("clock_get: timeh %08x timel %08x\n", timeh
, timel
));
294 tvp
->tv_sec
+= timel
/ ETIME_L_HZ
;
296 /* scale from 32kHz to 1MHz */
297 usec
= (timel
% ETIME_L_HZ
);
300 tvp
->tv_usec
= (uint32_t)usec
;
306 vrrtc_set(todr_chip_handle_t tch
, struct timeval
*tvp
)
308 struct vrrtc_softc
*sc
= (struct vrrtc_softc
*)tch
->cookie
;
309 bus_space_tag_t iot
= sc
->sc_iot
;
310 bus_space_handle_t ioh
= sc
->sc_ioh
;
311 u_int32_t timeh
; /* elapse time (2*timeh sec) */
312 u_int32_t timel
; /* timel/32768 sec */
315 sec
= tvp
->tv_sec
+ sc
->sc_epoch
;
317 timeh
= EPOCHOFF
+ (sec
/ 2);
321 /* scale from 1MHz to 32kHz */
324 timel
+= (uint32_t)cnt
;
326 bus_space_write_2(iot
, ioh
, ETIME_H_REG_W
, (timeh
>> 16) & 0xffff);
327 bus_space_write_2(iot
, ioh
, ETIME_M_REG_W
, timeh
& 0xffff);
328 bus_space_write_2(iot
, ioh
, ETIME_L_REG_W
, timel
);
334 vrrtc_dump_regs(struct vrrtc_softc
*sc
)
339 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ETIME_H_REG_W
);
340 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ETIME_M_REG_W
);
341 timel
= (timel
<< 16)
342 | bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ETIME_L_REG_W
);
343 printf("clock_init() Elapse Time %04x%04x\n", timeh
, timel
);
345 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_H_REG_W
);
346 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_M_REG_W
);
347 timel
= (timel
<< 16)
348 | bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, ECMP_L_REG_W
);
349 printf("clock_init() Elapse Compare %04x%04x\n", timeh
, timel
);
351 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_H_REG_W
);
352 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_L_REG_W
);
353 printf("clock_init() LONG1 %04x%04x\n", timeh
, timel
);
355 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_CNT_H_REG_W
);
356 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL1_CNT_L_REG_W
);
357 printf("clock_init() LONG1 CNTL %04x%04x\n", timeh
, timel
);
359 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_H_REG_W
);
360 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_L_REG_W
);
361 printf("clock_init() LONG2 %04x%04x\n", timeh
, timel
);
363 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_CNT_H_REG_W
);
364 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, RTCL2_CNT_L_REG_W
);
365 printf("clock_init() LONG2 CNTL %04x%04x\n", timeh
, timel
);
367 if (TCLK_H_REG_W
!= RTC_NO_REG_W
) {
368 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_H_REG_W
);
369 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_L_REG_W
);
370 printf("clock_init() TCLK %04x%04x\n", timeh
, timel
);
372 timeh
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_CNT_H_REG_W
);
373 timel
= bus_space_read_2(sc
->sc_iot
, sc
->sc_ioh
, TCLK_CNT_L_REG_W
);
374 printf("clock_init() TCLK CNTL %04x%04x\n", timeh
, timel
);