tctrl.c revision 1.3 1 /* $NetBSD: tctrl.c,v 1.3 1999/11/21 15:23:02 pk Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas.
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 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/ioctl.h>
42 #include <sys/select.h>
43 #include <sys/tty.h>
44 #include <sys/proc.h>
45 #include <sys/user.h>
46 #include <sys/conf.h>
47 #include <sys/file.h>
48 #include <sys/uio.h>
49 #include <sys/kernel.h>
50 #include <sys/syslog.h>
51 #include <sys/types.h>
52 #include <sys/device.h>
53
54 #include <machine/autoconf.h>
55 #include <machine/cpu.h>
56 #include <machine/bus.h>
57
58 #include <sparc/dev/ts102reg.h>
59 #include <sparc/dev/tctrlvar.h>
60
61 static const char *tctrl_ext_statuses[16] = {
62 "main power available",
63 "internal battery attached",
64 "external battery attached",
65 "external VGA attached",
66 "external keyboard attached",
67 "external mouse attached",
68 "lid down",
69 "internal battery charging",
70 "external battery charging",
71 "internal battery discharging",
72 "external battery discharging",
73 };
74
75 struct tctrl_softc {
76 struct device sc_dev;
77 bus_space_tag_t sc_memt;
78 bus_space_handle_t sc_memh;
79 unsigned int sc_junk;
80 unsigned int sc_ext_status;
81 unsigned int sc_pending;
82 #define TCTRL_SEND_BITPORT 0x0001
83 #define TCTRL_SEND_POWEROFF 0x0002
84 #define TCTRL_SEND_RD_EXT_STATUS 0x0004
85 #define TCTRL_SEND_RD_EVENT_STATUS 0x0008
86 #define TCTRL_SEND_BITPORT_NOP 0x0010
87 enum { TCTRL_IDLE, TCTRL_ARGS,
88 TCTRL_ACK, TCTRL_DATA } sc_state;
89 u_int8_t sc_cmdbuf[16];
90 u_int8_t sc_rspbuf[16];
91 u_int8_t sc_bitport;
92 u_int8_t sc_tft_on;
93 u_int8_t sc_op;
94 u_int8_t sc_cmdoff;
95 u_int8_t sc_cmdlen;
96 u_int8_t sc_rspoff;
97 u_int8_t sc_rsplen;
98
99 struct evcnt sc_intrcnt; /* interrupt counting */
100 };
101
102 static int tctrl_match(struct device *parent, struct cfdata *cf, void *aux);
103 static void tctrl_attach(struct device *parent, struct device *self, void *aux);
104
105 static void tctrl_write(struct tctrl_softc *sc, bus_size_t off, u_int8_t v);
106 static u_int8_t tctrl_read(struct tctrl_softc *sc, bus_size_t off);
107 static void tctrl_write_data(struct tctrl_softc *sc, u_int8_t v);
108 static u_int8_t tctrl_read_data(struct tctrl_softc *sc);
109 static int tctrl_intr(void *arg);
110 static void tctrl_setup_bitport(struct tctrl_softc *sc, int nop);
111 static void tctrl_process_response(struct tctrl_softc *sc);
112
113 struct cfattach tctrl_ca = {
114 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
115 };
116
117 extern struct cfdriver tctrl_cd;
118
119 static int
120 tctrl_match(struct device *parent, struct cfdata *cf, void *aux)
121 {
122 union obio_attach_args *uoba = aux;
123 struct sbus_attach_args *sa = &uoba->uoba_sbus;
124
125 if (uoba->uoba_isobio4 != 0) {
126 return (0);
127 }
128
129 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
130 * (who's interface is off the TS102 PCMCIA controller but there
131 * exists a OpenProm for microcontroller interface).
132 */
133 return strcmp("uctrl", sa->sa_name) == 0;
134 }
135
136 static void
137 tctrl_attach(struct device *parent, struct device *self, void *aux)
138 {
139 struct tctrl_softc *sc = (void *)self;
140 union obio_attach_args *uoba = aux;
141 struct sbus_attach_args *sa = &uoba->uoba_sbus;
142 unsigned int i, v;
143 #if 0
144 unsigned int ack, msb, lsb;
145 #endif
146
147 /* We're living on a sbus slot that looks like an obio that
148 * looks like an sbus slot.
149 */
150 sc->sc_memt = sa->sa_bustag;
151 if (sbus_bus_map(sc->sc_memt, sa->sa_slot,
152 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size,
153 BUS_SPACE_MAP_LINEAR, 0,
154 &sc->sc_memh) != 0) {
155 printf(": can't map registers\n");
156 return;
157 }
158
159 printf("\n");
160
161 sc->sc_tft_on = 1;
162
163 /* clear any pending data.
164 */
165 for (i = 0; i < 10000; i++) {
166 if ((TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
167 break;
168 }
169 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
170 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
171 }
172
173 if (sa->sa_nintr != 0) {
174 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri,
175 0, tctrl_intr, sc);
176 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
177 }
178
179 /* See what the external status is
180 */
181 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
182 do {
183 tctrl_intr(sc);
184 } while (sc->sc_state != TCTRL_IDLE);
185
186 if (sc->sc_ext_status != 0) {
187 const char *sep;
188
189 printf("%s: ", sc->sc_dev.dv_xname);
190 v = sc->sc_ext_status;
191 for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
192 if (v & 1) {
193 printf("%s%s", sep, tctrl_ext_statuses[i]);
194 sep = ", ";
195 }
196 }
197 printf("\n");
198 }
199
200 /* Get a current of the control bitport;
201 */
202 sc->sc_pending |= TCTRL_SEND_BITPORT_NOP;
203 do {
204 tctrl_intr(sc);
205 } while (sc->sc_state != TCTRL_IDLE);
206
207 tctrl_write(sc, TS102_REG_UCTRL_INT,
208 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
209
210 }
211
212 static int
213 tctrl_intr(void *arg)
214 {
215 struct tctrl_softc *sc = arg;
216 unsigned int v, d;
217 int progress = 0;
218
219 again:
220 /* find out the cause(s) of the interrupt */
221 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
222
223 /* clear the cause(s) of the interrupt */
224 tctrl_write(sc, TS102_REG_UCTRL_STS, v);
225
226 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
227 if (sc->sc_cmdoff >= sc->sc_cmdlen) {
228 v &= ~TS102_UCTRL_STS_TXNF_STA;
229 }
230 if ((v == 0) && (sc->sc_pending == 0 || sc->sc_state != TCTRL_IDLE)) {
231 return progress;
232 }
233
234 progress = 1;
235 if (v & TS102_UCTRL_STS_RXNE_STA) {
236 d = tctrl_read_data(sc);
237 switch (sc->sc_state) {
238 case TCTRL_IDLE:
239 if (d == 0xfa) {
240 sc->sc_pending |= TCTRL_SEND_RD_EVENT_STATUS;
241 } else {
242 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
243 sc->sc_dev.dv_xname, sc->sc_op, d);
244 }
245 goto again;
246 case TCTRL_ACK:
247 if (d != 0xfe) {
248 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
249 sc->sc_dev.dv_xname, sc->sc_op, d);
250 }
251 #if 0
252 printf(" ack=0x%02x", d);
253 #endif
254 sc->sc_rsplen--;
255 sc->sc_rspoff = 0;
256 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
257 #if 0
258 if (sc->sc_rsplen > 0) {
259 printf(" [data(%u)]", sc->sc_rsplen);
260 } else {
261 printf(" [idle]\n");
262 }
263 #endif
264 goto again;
265 case TCTRL_DATA:
266 sc->sc_rspbuf[sc->sc_rspoff++] = d;
267 #if 0
268 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
269 #endif
270 if (sc->sc_rspoff == sc->sc_rsplen) {
271 #if 0
272 printf(" [idle]\n");
273 #endif
274 sc->sc_state = TCTRL_IDLE;
275 tctrl_process_response(sc);
276 }
277 goto again;
278 default:
279 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
280 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
281 goto again;
282 }
283 }
284 if (sc->sc_state == TCTRL_IDLE) {
285 sc->sc_cmdoff = 0;
286 sc->sc_cmdlen = 0;
287 if (sc->sc_pending & TCTRL_SEND_POWEROFF) {
288 sc->sc_pending &= ~TCTRL_SEND_POWEROFF;
289 sc->sc_cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
290 sc->sc_cmdlen = 1;
291 sc->sc_rsplen = 0;
292 } else if (sc->sc_pending & TCTRL_SEND_RD_EVENT_STATUS) {
293 sc->sc_pending &= ~TCTRL_SEND_RD_EVENT_STATUS;
294 sc->sc_cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
295 sc->sc_cmdlen = 1;
296 sc->sc_rsplen = 3;
297 } else if (sc->sc_pending & TCTRL_SEND_RD_EXT_STATUS) {
298 sc->sc_pending &= ~TCTRL_SEND_RD_EXT_STATUS;
299 sc->sc_cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
300 sc->sc_cmdlen = 1;
301 sc->sc_rsplen = 3;
302 } else if (sc->sc_pending & TCTRL_SEND_BITPORT_NOP) {
303 sc->sc_pending &= ~TCTRL_SEND_BITPORT_NOP;
304 tctrl_setup_bitport(sc, 1);
305 } else if (sc->sc_pending & TCTRL_SEND_BITPORT) {
306 sc->sc_pending &= ~TCTRL_SEND_BITPORT;
307 tctrl_setup_bitport(sc, 0);
308 }
309 if (sc->sc_cmdlen > 0) {
310 tctrl_write(sc, TS102_REG_UCTRL_INT,
311 tctrl_read(sc, TS102_REG_UCTRL_INT)
312 |TS102_UCTRL_INT_TXNF_MSK
313 |TS102_UCTRL_INT_TXNF_REQ);
314 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
315 }
316 }
317 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
318 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
319 #if 0
320 if (sc->sc_cmdoff == 1) {
321 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
322 sc->sc_cmdbuf[0], sc->sc_rsplen);
323 } else {
324 printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
325 sc->sc_cmdbuf[sc->sc_cmdoff-1]);
326 }
327 #endif
328 if (sc->sc_cmdoff == sc->sc_cmdlen) {
329 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
330 #if 0
331 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
332 #endif
333 if (sc->sc_cmdoff == 1) {
334 sc->sc_op = sc->sc_cmdbuf[0];
335 }
336 tctrl_write(sc, TS102_REG_UCTRL_INT,
337 tctrl_read(sc, TS102_REG_UCTRL_INT)
338 & (~TS102_UCTRL_INT_TXNF_MSK
339 |TS102_UCTRL_INT_TXNF_REQ));
340 } else if (sc->sc_state == TCTRL_IDLE) {
341 sc->sc_op = sc->sc_cmdbuf[0];
342 sc->sc_state = TCTRL_ARGS;
343 #if 0
344 printf(" [args]");
345 #endif
346 }
347 }
348 goto again;
349 }
350
351 static void
352 tctrl_setup_bitport(struct tctrl_softc *sc, int nop)
353 {
354 if (nop) {
355 sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT;
356 sc->sc_cmdbuf[1] = 0xff;
357 sc->sc_cmdbuf[2] = 0;
358 sc->sc_cmdlen = 3;
359 sc->sc_rsplen = 2;
360 } else {
361 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
362 || (!sc->sc_tft_on)) {
363 sc->sc_cmdbuf[2] = TS102_BITPORT_TFTPWR;
364 } else {
365 sc->sc_cmdbuf[2] = 0;
366 }
367 sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT;
368 sc->sc_cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
369 sc->sc_cmdlen = 3;
370 sc->sc_rsplen = 2;
371 }
372 }
373
374 static void
375 tctrl_process_response(struct tctrl_softc *sc)
376 {
377 switch (sc->sc_op) {
378 case TS102_OP_RD_EXT_STATUS: {
379 sc->sc_ext_status = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1];
380 break;
381 }
382 case TS102_OP_RD_EVENT_STATUS: {
383 unsigned int v = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1];
384 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
385 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
386 }
387 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
388 printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
389 }
390 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
391 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
392 }
393 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
394 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
395 printf("%s: main power %s\n", sc->sc_dev.dv_xname,
396 (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? "removed" : "restored");
397 }
398 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
399 sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
400 sc->sc_pending |= TCTRL_SEND_BITPORT;
401 #if 0
402 printf("%s: lid %s\n", sc->sc_dev.dv_xname,
403 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? "opened" : "closed");
404 #endif
405 }
406 break;
407 }
408 case TS102_OP_CTL_BITPORT:
409 sc->sc_bitport = (sc->sc_rspbuf[0] & sc->sc_cmdbuf[1]) ^ sc->sc_cmdbuf[2];
410 break;
411 default:
412 break;
413 }
414 }
415
416 void
417 tadpole_powerdown(void)
418 {
419 struct tctrl_softc *sc;
420 int i, s;
421
422 if (tctrl_cd.cd_devs == NULL
423 || tctrl_cd.cd_ndevs == 0
424 || tctrl_cd.cd_devs[0] == NULL) {
425 return;
426 }
427
428 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0];
429 s = splhigh();
430 sc->sc_pending |= TCTRL_SEND_POWEROFF;
431 for (i = 0; i < 10000; i++) {
432 tctrl_intr(sc);
433 DELAY(1);
434 }
435 splx(s);
436 }
437
438 void
439 tadpole_set_video(int enabled)
440 {
441 struct tctrl_softc *sc;
442 int s;
443
444 if (tctrl_cd.cd_devs == NULL
445 || tctrl_cd.cd_ndevs == 0
446 || tctrl_cd.cd_devs[0] == NULL) {
447 return;
448 }
449
450 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0];
451 s = splhigh();
452 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
453 sc->sc_tft_on = enabled;
454 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
455 splx(s);
456 return;
457 }
458 sc->sc_pending |= TCTRL_SEND_BITPORT;
459 tctrl_intr(sc);
460 }
461 splx(s);
462 }
463
464 static void
465 tctrl_write_data(struct tctrl_softc *sc, u_int8_t v)
466 {
467 unsigned int i;
468 for (i = 0; i < 100; i++) {
469 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
470 break;
471 }
472 tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
473 }
474
475 static u_int8_t
476 tctrl_read_data(struct tctrl_softc *sc)
477 {
478 unsigned int i, v;
479
480 for (i = 0; i < 100000; i++) {
481 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
482 break;
483 DELAY(1);
484 }
485
486 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
487 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
488 return v;
489 }
490
491 static u_int8_t
492 tctrl_read(struct tctrl_softc *sc, bus_size_t off)
493 {
494 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
495 return sc->sc_junk;
496 }
497
498 static void
499 tctrl_write(struct tctrl_softc *sc, bus_size_t off, u_int8_t v)
500 {
501 sc->sc_junk = v;
502 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
503 }
504