1 /*	$OpenBSD: scf.c,v 1.6 2003/06/02 18:40:59 jason Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * This software was developed by Jason L. Wright under contract with
8  * RTMX Incorporated (http://www.rtmx.com).
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Driver for the flash memory and sysconfig registers found on Force CPU-5V
34  * boards.
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/errno.h>
41 #include <sys/ioctl.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/syslog.h>
45 #include <sys/device.h>
46 #include <sys/malloc.h>
47 #include <sys/timeout.h>
48 
49 #include <machine/autoconf.h>
50 #include <sparc/cpu.h>
51 #include <sparc/sparc/cpuvar.h>
52 #include <machine/scfio.h>
53 #include <sparc/dev/scfreg.h>
54 
55 int	scfmatch(struct device *, void *, void *);
56 void	scfattach(struct device *, struct device *, void *);
57 
58 int	scfopen(dev_t, int, int, struct proc *);
59 int	scfclose(dev_t, int, int, struct proc *);
60 int	scfioctl(dev_t, u_long, caddr_t, int, struct proc *);
61 
62 struct scf_softc {
63 	struct	device sc_dv;			/* base device */
64 	struct	scf_regs *sc_regs;	/* our registers */
65 	int	sc_open;
66 	int	sc_tick;
67 	struct	timeout sc_blink_tmo;	/* for scfblink() */
68 };
69 
70 struct cfattach scf_ca = {
71 	sizeof (struct scf_softc), scfmatch, scfattach
72 };
73 
74 struct cfdriver scf_cd = {
75 	NULL, "sysconfig", DV_IFNET
76 };
77 
78 extern int sparc_led_blink;
79 
80 static u_int8_t scf_pattern[] = {
81 	SSLDCR_A|SSLDCR_B|SSLDCR_C|SSLDCR_D|SSLDCR_E|SSLDCR_F,
82 	SSLDCR_B|SSLDCR_C,
83 	SSLDCR_A|SSLDCR_B|SSLDCR_D|SSLDCR_E|SSLDCR_G,
84 	SSLDCR_A|SSLDCR_B|SSLDCR_C|SSLDCR_D|SSLDCR_G,
85 	SSLDCR_B|SSLDCR_C|SSLDCR_F|SSLDCR_G,
86 	SSLDCR_A|SSLDCR_C|SSLDCR_D|SSLDCR_F|SSLDCR_G,
87 	SSLDCR_A|SSLDCR_C|SSLDCR_D|SSLDCR_E|SSLDCR_F|SSLDCR_G,
88 	SSLDCR_A|SSLDCR_B|SSLDCR_C,
89 	SSLDCR_A|SSLDCR_B|SSLDCR_C|SSLDCR_D|SSLDCR_E|SSLDCR_F|SSLDCR_G,
90 	SSLDCR_A|SSLDCR_B|SSLDCR_C|SSLDCR_D|SSLDCR_F|SSLDCR_G,
91 	SSLDCR_A|SSLDCR_B|SSLDCR_C|SSLDCR_E|SSLDCR_F|SSLDCR_G,
92 	SSLDCR_C|SSLDCR_D|SSLDCR_E|SSLDCR_F|SSLDCR_G,
93 	SSLDCR_A|SSLDCR_D|SSLDCR_E|SSLDCR_F,
94 	SSLDCR_B|SSLDCR_C|SSLDCR_D|SSLDCR_E|SSLDCR_G,
95 	SSLDCR_A|SSLDCR_D|SSLDCR_E|SSLDCR_F|SSLDCR_G,
96 	SSLDCR_A|SSLDCR_E|SSLDCR_F|SSLDCR_G,
97 };
98 
99 int
scfmatch(parent,vcf,aux)100 scfmatch(parent, vcf, aux)
101 	struct device *parent;
102 	void *vcf, *aux;
103 {
104 	struct confargs *ca = aux;
105 	register struct romaux *ra = &ca->ca_ra;
106 
107 	if (strcmp("sysconfig", ra->ra_name))
108 		return (0);
109 
110 	return (1);
111 }
112 
113 void
scfattach(parent,self,aux)114 scfattach(parent, self, aux)
115 	struct device *parent, *self;
116 	void *aux;
117 {
118 	struct confargs *ca = aux;
119 	struct scf_softc *sc = (struct scf_softc *)self;
120 	char *s;
121 
122 	/* map registers */
123 	if (ca->ca_ra.ra_nreg != 1) {
124 		printf(": expected 1 register, got %d\n", ca->ca_ra.ra_nreg);
125 		return;
126 	}
127 
128 	sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
129 			ca->ca_ra.ra_reg[0].rr_len);
130 
131 	s = getpropstring(ca->ca_ra.ra_node, "model");
132 	printf(": model %s\n", s);
133 
134 	sc->sc_regs->led1 &= ~LED_MASK;
135 	sc->sc_regs->led1 &= ~LED_MASK;
136 	sc->sc_regs->ssldcr = 0;
137 
138 	timeout_set(&sc->sc_blink_tmo, scfblink, 0);
139 
140 	if (sparc_led_blink)
141 		scfblink(0);
142 }
143 
144 int
scfopen(dev,flags,mode,p)145 scfopen(dev, flags, mode, p)
146 	dev_t dev;
147 	int flags;
148 	int mode;
149 	struct proc *p;
150 {
151 	struct scf_softc *sc;
152 	int card = 0;
153 
154 	if (card >= scf_cd.cd_ndevs)
155 		return (ENXIO);
156 
157 	sc = scf_cd.cd_devs[card];
158 	if (sc->sc_open)
159 		return (EBUSY);
160 
161 	sc->sc_open = 1;
162 	return (0);
163 }
164 
165 int
scfclose(dev,flags,mode,p)166 scfclose(dev, flags, mode, p)
167 	dev_t dev;
168 	int flags;
169 	int mode;
170 	struct proc *p;
171 {
172 	struct scf_softc *sc;
173 	int card = 0;
174 
175 	sc = scf_cd.cd_devs[card];
176 	sc->sc_open = 0;
177 	return (0);
178 }
179 
180 int
scfioctl(dev,cmd,data,flags,p)181 scfioctl(dev, cmd, data, flags, p)
182 	dev_t dev;
183 	u_long cmd;
184 	caddr_t data;
185 	int flags;
186 	struct proc *p;
187 {
188 	struct scf_softc *sc = scf_cd.cd_devs[0];
189 	u_int8_t *ptr = (u_int8_t *)data, c;
190 	int error = 0;
191 
192 	switch (cmd) {
193 	case SCFIOCSLED1:
194 		sc->sc_regs->led1 = LED_MASK | (*ptr);
195 		break;
196 	case SCFIOCGLED1:
197 		*ptr = sc->sc_regs->led1 & (LED_COLOR_MASK | LED_BLINK_MASK);
198 		break;
199 	case SCFIOCSLED2:
200 		sc->sc_regs->led2 = LED_MASK | (*ptr);
201 		break;
202 	case SCFIOCGLED2:
203 		*ptr = sc->sc_regs->led2 & (LED_COLOR_MASK | LED_BLINK_MASK);
204 		break;
205 	case SCFIOCSLED7:
206 		sc->sc_regs->ssldcr = *ptr;
207 		break;
208 	case SCFIOCGLED7:
209 		*ptr = sc->sc_regs->ssldcr;
210 		break;
211 	case SCFIOCGROT:
212 		*ptr = sc->sc_regs->rssr;
213 		break;
214 	case SCFIOCSFMCTRL:
215 		if ((*ptr) & SCF_FMCTRL_SELROM)
216 			sc->sc_regs->fmpcr1 |= FMPCR1_SELROM;
217 		else
218 			sc->sc_regs->fmpcr1 &= ~FMPCR1_SELROM;
219 
220 		if ((*ptr) & SCF_FMCTRL_SELBOOT)
221 			sc->sc_regs->fmpcr2 |= FMPCR2_SELBOOT;
222 		else
223 			sc->sc_regs->fmpcr2 &= ~FMPCR2_SELBOOT;
224 
225 		if ((*ptr) & SCF_FMCTRL_WRITEV)
226 			sc->sc_regs->fmpvcr |= FMPVCR_VPP;
227 		else
228 			sc->sc_regs->fmpvcr &= ~FMPVCR_VPP;
229 
230 		c = ((*ptr) & SCF_FMCTRL_SELADDR) >> 3;
231 		sc->sc_regs->fmpcr1 =
232 		    (sc->sc_regs->fmpcr1 & ~FMPCR1_SELADDR) | (c << 1);
233 
234 		break;
235 	case SCFIOCGFMCTRL:
236 		c = (sc->sc_regs->fmpcr1 & FMPCR1_SELADDR) << 2;
237 		if (sc->sc_regs->fmpcr1 & FMPCR1_SELROM)
238 			c |= SCF_FMCTRL_SELROM;
239 		if (sc->sc_regs->fmpcr2 & FMPCR2_SELBOOT)
240 			c |= SCF_FMCTRL_SELBOOT;
241 		if (sc->sc_regs->fmpvcr & FMPVCR_VPP)
242 			c |= SCF_FMCTRL_WRITEV;
243 		*ptr = c;
244 		break;
245 	default:
246 		error = ENOTTY;
247 	}
248 
249 	return (error);
250 }
251 
252 void
scfblink(v)253 scfblink(v)
254         void *v;
255 {
256 	struct scf_softc *sc;
257 	int s, avg, hi = 0;
258 
259 	if (scf_cd.cd_ndevs == 0)
260 		return;
261 
262 	sc = scf_cd.cd_devs[0];
263 	if (sc == NULL)
264 		return;
265 
266 	if (sparc_led_blink == 0) {
267 		sc->sc_regs->led1 &= ~LED_MASK;
268 		sc->sc_regs->led2 &= ~LED_MASK;
269 		sc->sc_regs->ssldcr = 0;
270 		return;
271 	}
272 
273 	avg = averunnable.ldavg[0] >> FSHIFT;
274 	while (avg > 15) {
275 		hi = 1;
276 		avg >>= 4;
277 	}
278 
279 	s = splhigh();
280 	if (sc->sc_tick & 1) {
281 		sc->sc_regs->led1 &= ~LED_MASK;
282 		sc->sc_regs->led2 |= LED_COLOR_GREEN;
283 	}
284 	else {
285 		sc->sc_regs->led1 |= LED_COLOR_YELLOW;
286 		sc->sc_regs->led2 &= ~LED_MASK;
287 	}
288 	sc->sc_regs->ssldcr = scf_pattern[avg] | (hi ? SSLDCR_P : 0);
289 	splx(s);
290 
291 	sc->sc_tick++;
292 
293 	s = ((averunnable.ldavg[0] + FSCALE) * hz) >> (FSHIFT + 1);
294 	timeout_add(&sc->sc_blink_tmo, s);
295 }
296