xref: /netbsd-src/sys/dev/mvme/clock_pcctwo.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: clock_pcctwo.c,v 1.5 2003/07/14 15:47:19 lukem Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Steve C. Woodford.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
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.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Glue for the Peripheral Channel Controller Two (PCCChip2) timers,
41  * the Memory Controller ASIC (MCchip, and the Mostek clock chip found
42  * on the MVME-1[67]7, MVME-1[67]2 and MVME-187 series of boards.
43  */
44 
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: clock_pcctwo.c,v 1.5 2003/07/14 15:47:19 lukem Exp $");
47 
48 #include <sys/param.h>
49 #include <sys/kernel.h>
50 #include <sys/systm.h>
51 #include <sys/device.h>
52 
53 #include <machine/psl.h>
54 #include <machine/bus.h>
55 
56 #include <dev/mvme/clockvar.h>
57 #include <dev/mvme/pcctwovar.h>
58 #include <dev/mvme/pcctworeg.h>
59 
60 
61 int clock_pcctwo_match __P((struct device *, struct cfdata *, void *));
62 void clock_pcctwo_attach __P((struct device *, struct device *, void *));
63 
64 struct clock_pcctwo_softc {
65 	struct device sc_dev;
66 	struct clock_attach_args sc_clock_args;
67 	u_char sc_clock_lvl;
68 };
69 
70 CFATTACH_DECL(clock_pcctwo, sizeof(struct device),
71     clock_pcctwo_match, clock_pcctwo_attach, NULL, NULL);
72 
73 extern struct cfdriver clock_cd;
74 
75 static int clock_pcctwo_profintr __P((void *));
76 static int clock_pcctwo_statintr __P((void *));
77 static void clock_pcctwo_initclocks __P((void *, int, int));
78 static long clock_pcctwo_microtime __P((void *));
79 static void clock_pcctwo_shutdown __P((void *));
80 
81 static struct clock_pcctwo_softc *clock_pcctwo_sc;
82 
83 /* ARGSUSED */
84 int
85 clock_pcctwo_match(parent, cf, aux)
86 	struct device *parent;
87 	struct cfdata *cf;
88 	void *aux;
89 {
90 	struct pcctwo_attach_args *pa = aux;
91 
92 	/* Only one clock, please. */
93 	if (clock_pcctwo_sc)
94 		return (0);
95 
96 	if (strcmp(pa->pa_name, clock_cd.cd_name))
97 		return (0);
98 
99 	pa->pa_ipl = cf->pcctwocf_ipl;
100 
101 	return (1);
102 }
103 
104 /* ARGSUSED */
105 void
106 clock_pcctwo_attach(parent, self, aux)
107 	struct device *parent;
108 	struct device *self;
109 	void *aux;
110 {
111 	struct clock_pcctwo_softc *sc;
112 	struct pcctwo_attach_args *pa;
113 
114 	sc = clock_pcctwo_sc = (struct clock_pcctwo_softc *) self;
115 	pa = aux;
116 
117 	if (pa->pa_ipl != CLOCK_LEVEL)
118 		panic("clock_pcctwo_attach: wrong interrupt level");
119 
120 	sc->sc_clock_args.ca_arg = sc;
121 	sc->sc_clock_args.ca_initfunc = clock_pcctwo_initclocks;
122 	sc->sc_clock_args.ca_microtime = clock_pcctwo_microtime;
123 
124 	/* Do common portions of clock config. */
125 	clock_config(self, &sc->sc_clock_args, pcctwointr_evcnt(pa->pa_ipl));
126 
127 	/* Ensure our interrupts get disabled at shutdown time. */
128 	(void) shutdownhook_establish(clock_pcctwo_shutdown, NULL);
129 
130 	sc->sc_clock_lvl = (pa->pa_ipl & PCCTWO_ICR_LEVEL_MASK) |
131 	    PCCTWO_ICR_ICLR | PCCTWO_ICR_IEN;
132 
133 	/* Attach the interrupt handlers. */
134 	pcctwointr_establish(PCCTWOV_TIMER1, clock_pcctwo_profintr,
135 	    pa->pa_ipl, NULL, &clock_profcnt);
136 	pcctwointr_establish(PCCTWOV_TIMER2, clock_pcctwo_statintr,
137 	    pa->pa_ipl, NULL, &clock_statcnt);
138 }
139 
140 void
141 clock_pcctwo_initclocks(arg, proftick, stattick)
142 	void *arg;
143 	int proftick;
144 	int stattick;
145 {
146 	struct clock_pcctwo_softc *sc;
147 
148 	sc = arg;
149 
150 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
151 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COUNTER, 0);
152 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER1_COMPARE,
153 	    PCCTWO_US2LIM(proftick));
154 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
155 	    PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
156 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, sc->sc_clock_lvl);
157 
158 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
159 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
160 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
161 	    PCCTWO_US2LIM(stattick));
162 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
163 	    PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
164 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, sc->sc_clock_lvl);
165 }
166 
167 /* ARGSUSED */
168 long
169 clock_pcctwo_microtime(arg)
170 	void *arg;
171 {
172 	static int ovfl_adj[] = {
173 		0,       10000,  20000,  30000,
174 		40000,   50000,  60000,  70000,
175 		80000,   90000, 100000, 110000,
176 		120000, 130000, 140000, 150000};
177 	u_int8_t cr;
178 	u_int32_t tc, tc2;
179 
180 	/*
181 	 * There's no way to latch the counter and overflow registers
182 	 * without pausing the clock, so compensate for the possible
183 	 * race by checking for counter wrap-around and re-reading the
184 	 * overflow counter if necessary.
185 	 *
186 	 * Note: This only works because we're called at splhigh().
187 	 */
188 	tc = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
189 	cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
190 	if (tc > (tc2 = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER))) {
191 		cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
192 		tc = tc2;
193 	}
194 
195 	return ((long) PCCTWO_LIM2US(tc) + ovfl_adj[PCCTWO_TT_CTRL_OVF(cr)]);
196 }
197 
198 int
199 clock_pcctwo_profintr(frame)
200 	void *frame;
201 {
202 	u_int8_t cr;
203 	u_int32_t tc;
204 	int s;
205 
206 	s = splhigh();
207 	tc = pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER);
208 	cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
209 	if (tc > pcc2_reg_read32(sys_pcctwo, PCC2REG_TIMER1_COUNTER))
210 		cr = pcc2_reg_read(sys_pcctwo, PCC2REG_TIMER1_CONTROL);
211 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL,
212 	    PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
213 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR,
214 	    clock_pcctwo_sc->sc_clock_lvl);
215 	splx(s);
216 
217 	for (cr = PCCTWO_TT_CTRL_OVF(cr); cr; cr--)
218 		hardclock(frame);
219 
220 	return (1);
221 }
222 
223 int
224 clock_pcctwo_statintr(frame)
225 	void *frame;
226 {
227 
228 	/* Disable the timer interrupt while we handle it. */
229 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
230 
231 	statclock((struct clockframe *) frame);
232 
233 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
234 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COUNTER, 0);
235 	pcc2_reg_write32(sys_pcctwo, PCC2REG_TIMER2_COMPARE,
236 	    PCCTWO_US2LIM(CLOCK_NEWINT(clock_statvar, clock_statmin)));
237 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL,
238 	    PCCTWO_TT_CTRL_CEN | PCCTWO_TT_CTRL_COC | PCCTWO_TT_CTRL_COVF);
239 
240 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR,
241 	    clock_pcctwo_sc->sc_clock_lvl);
242 
243 	return (1);
244 }
245 
246 /* ARGSUSED */
247 void
248 clock_pcctwo_shutdown(arg)
249 	void *arg;
250 {
251 
252 	/* Make sure the timer interrupts are turned off. */
253 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_CONTROL, PCCTWO_TT_CTRL_COVF);
254 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER1_ICSR, 0);
255 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_CONTROL, PCCTWO_TT_CTRL_COVF);
256 	pcc2_reg_write(sys_pcctwo, PCC2REG_TIMER2_ICSR, 0);
257 }
258