1 /* $NetBSD: clock_pcctwo.c,v 1.15 2009/05/12 13:16:45 cegger Exp $ */
4 * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Steve C. Woodford.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Glue for the Peripheral Channel Controller Two (PCCChip2) timers,
34 * the Memory Controller ASIC (MCchip, and the Mostek clock chip found
35 * on the MVME-1[67]7, MVME-1[67]2 and MVME-187 series of boards.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: clock_pcctwo.c,v 1.15 2009/05/12 13:16:45 cegger Exp $");
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
44 #include <sys/device.h>
45 #include <sys/timetc.h>
47 #include <machine/psl.h>
50 #include <dev/mvme/clockvar.h>
51 #include <dev/mvme/pcctwovar.h>
52 #include <dev/mvme/pcctworeg.h>
55 int clock_pcctwo_match(device_t
, cfdata_t
, void *);
56 void clock_pcctwo_attach(device_t
, device_t
, void *);
58 struct clock_pcctwo_softc
{
60 struct clock_attach_args sc_clock_args
;
62 struct timecounter sc_tc
;
65 CFATTACH_DECL(clock_pcctwo
, sizeof(struct clock_pcctwo_softc
),
66 clock_pcctwo_match
, clock_pcctwo_attach
, NULL
, NULL
);
68 extern struct cfdriver clock_cd
;
70 static int clock_pcctwo_profintr(void *);
71 static int clock_pcctwo_statintr(void *);
72 static void clock_pcctwo_initclocks(void *, int, int);
73 static u_int
clock_pcctwo_getcount(struct timecounter
*);
74 static void clock_pcctwo_shutdown(void *);
76 static struct clock_pcctwo_softc
*clock_pcctwo_sc
;
77 static uint32_t clock_pcctwo_count
;
81 clock_pcctwo_match(device_t parent
, cfdata_t cf
, void *aux
)
83 struct pcctwo_attach_args
*pa
= aux
;
85 /* Only one clock, please. */
89 if (strcmp(pa
->pa_name
, clock_cd
.cd_name
))
92 pa
->pa_ipl
= cf
->pcctwocf_ipl
;
99 clock_pcctwo_attach(device_t parent
, device_t self
, void *aux
)
101 struct clock_pcctwo_softc
*sc
;
102 struct pcctwo_attach_args
*pa
;
104 sc
= clock_pcctwo_sc
= device_private(self
);
107 if (pa
->pa_ipl
!= CLOCK_LEVEL
)
108 panic("clock_pcctwo_attach: wrong interrupt level");
110 sc
->sc_clock_args
.ca_arg
= sc
;
111 sc
->sc_clock_args
.ca_initfunc
= clock_pcctwo_initclocks
;
113 /* Do common portions of clock config. */
114 clock_config(self
, &sc
->sc_clock_args
, pcctwointr_evcnt(pa
->pa_ipl
));
116 /* Ensure our interrupts get disabled at shutdown time. */
117 (void) shutdownhook_establish(clock_pcctwo_shutdown
, NULL
);
119 sc
->sc_clock_lvl
= (pa
->pa_ipl
& PCCTWO_ICR_LEVEL_MASK
) |
120 PCCTWO_ICR_ICLR
| PCCTWO_ICR_IEN
;
122 /* Attach the interrupt handlers. */
123 pcctwointr_establish(PCCTWOV_TIMER1
, clock_pcctwo_profintr
,
124 pa
->pa_ipl
, NULL
, &clock_profcnt
);
125 pcctwointr_establish(PCCTWOV_TIMER2
, clock_pcctwo_statintr
,
126 pa
->pa_ipl
, NULL
, &clock_statcnt
);
130 clock_pcctwo_initclocks(void *arg
, int prof_us
, int stat_us
)
132 struct clock_pcctwo_softc
*sc
;
136 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
, PCCTWO_TT_CTRL_COVF
);
137 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER1_COUNTER
, 0);
138 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER1_COMPARE
,
139 PCCTWO_US2LIM(prof_us
));
140 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
,
141 PCCTWO_TT_CTRL_CEN
| PCCTWO_TT_CTRL_COC
| PCCTWO_TT_CTRL_COVF
);
142 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_ICSR
, sc
->sc_clock_lvl
);
144 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_CONTROL
, PCCTWO_TT_CTRL_COVF
);
145 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER2_COUNTER
, 0);
146 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER2_COMPARE
,
147 PCCTWO_US2LIM(stat_us
));
148 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_CONTROL
,
149 PCCTWO_TT_CTRL_CEN
| PCCTWO_TT_CTRL_COC
| PCCTWO_TT_CTRL_COVF
);
150 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_ICSR
, sc
->sc_clock_lvl
);
152 sc
->sc_tc
.tc_get_timecount
= clock_pcctwo_getcount
;
153 sc
->sc_tc
.tc_name
= "pcctwo_count";
154 sc
->sc_tc
.tc_frequency
= PCCTWO_TIMERFREQ
;
155 sc
->sc_tc
.tc_quality
= 100;
156 sc
->sc_tc
.tc_counter_mask
= ~0;
162 clock_pcctwo_getcount(struct timecounter
*tc
)
172 * There's no way to latch the counter and overflow registers
173 * without pausing the clock, so compensate for the possible
174 * race by checking for counter wrap-around and re-reading the
175 * overflow counter if necessary.
177 * Note: This only works because we're at splhigh().
179 tc1
= pcc2_reg_read32(sys_pcctwo
, PCC2REG_TIMER1_COUNTER
);
180 cr
= pcc2_reg_read(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
);
181 tc2
= pcc2_reg_read32(sys_pcctwo
, PCC2REG_TIMER1_COUNTER
);
183 cr
= pcc2_reg_read(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
);
186 cnt
= clock_pcctwo_count
;
188 /* XXX assume HZ == 100 */
189 cnt
+= tc1
+ (PCCTWO_TIMERFREQ
/ 100) * PCCTWO_TT_CTRL_OVF(cr
);
195 clock_pcctwo_profintr(void *frame
)
202 tc
= pcc2_reg_read32(sys_pcctwo
, PCC2REG_TIMER1_COUNTER
);
203 cr
= pcc2_reg_read(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
);
204 if (tc
> pcc2_reg_read32(sys_pcctwo
, PCC2REG_TIMER1_COUNTER
))
205 cr
= pcc2_reg_read(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
);
206 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
,
207 PCCTWO_TT_CTRL_CEN
| PCCTWO_TT_CTRL_COC
| PCCTWO_TT_CTRL_COVF
);
208 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_ICSR
,
209 clock_pcctwo_sc
->sc_clock_lvl
);
212 for (cr
= PCCTWO_TT_CTRL_OVF(cr
); cr
; cr
--) {
213 /* XXX assume HZ == 100 */
214 clock_pcctwo_count
+= PCCTWO_TIMERFREQ
/ 100;
222 clock_pcctwo_statintr(void *frame
)
225 /* Disable the timer interrupt while we handle it. */
226 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_ICSR
, 0);
228 statclock((struct clockframe
*) frame
);
230 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_CONTROL
, PCCTWO_TT_CTRL_COVF
);
231 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER2_COUNTER
, 0);
232 pcc2_reg_write32(sys_pcctwo
, PCC2REG_TIMER2_COMPARE
,
233 PCCTWO_US2LIM(CLOCK_NEWINT(clock_statvar
, clock_statmin
)));
234 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_CONTROL
,
235 PCCTWO_TT_CTRL_CEN
| PCCTWO_TT_CTRL_COC
| PCCTWO_TT_CTRL_COVF
);
237 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_ICSR
,
238 clock_pcctwo_sc
->sc_clock_lvl
);
245 clock_pcctwo_shutdown(void *arg
)
248 /* Make sure the timer interrupts are turned off. */
249 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_CONTROL
, PCCTWO_TT_CTRL_COVF
);
250 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER1_ICSR
, 0);
251 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_CONTROL
, PCCTWO_TT_CTRL_COVF
);
252 pcc2_reg_write(sys_pcctwo
, PCC2REG_TIMER2_ICSR
, 0);