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