Home | History | Annotate | Line # | Download | only in dev
tctrl.c revision 1.2
      1 /*	$NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt 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 	(void)bus_intr_establish(sc->sc_memt, sa->sa_pri, 0, tctrl_intr, sc);
    174 	evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
    175 
    176 	/* See what the external status is
    177 	 */
    178 	sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
    179 	do {
    180 		tctrl_intr(sc);
    181 	} while (sc->sc_state != TCTRL_IDLE);
    182 
    183 	if (sc->sc_ext_status != 0) {
    184 		const char *sep;
    185 
    186 		printf("%s: ", sc->sc_dev.dv_xname);
    187 		v = sc->sc_ext_status;
    188 		for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
    189 			if (v & 1) {
    190 				printf("%s%s", sep, tctrl_ext_statuses[i]);
    191 				sep = ", ";
    192 			}
    193 		}
    194 		printf("\n");
    195 	}
    196 
    197 	/* Get a current of the control bitport;
    198 	 */
    199 	sc->sc_pending |= TCTRL_SEND_BITPORT_NOP;
    200 	do {
    201 		tctrl_intr(sc);
    202 	} while (sc->sc_state != TCTRL_IDLE);
    203 
    204 	tctrl_write(sc, TS102_REG_UCTRL_INT,
    205 		    TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
    206 
    207 }
    208 
    209 static int
    210 tctrl_intr(void *arg)
    211 {
    212 	struct tctrl_softc *sc = arg;
    213 	unsigned int v, d;
    214 	int progress = 0;
    215 
    216     again:
    217 	/* find out the cause(s) of the interrupt */
    218 	v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    219 
    220 	/* clear the cause(s) of the interrupt */
    221 	tctrl_write(sc, TS102_REG_UCTRL_STS, v);
    222 
    223 	v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
    224 	if (sc->sc_cmdoff >= sc->sc_cmdlen) {
    225 		v &= ~TS102_UCTRL_STS_TXNF_STA;
    226 	}
    227 	if ((v == 0) && (sc->sc_pending == 0 || sc->sc_state != TCTRL_IDLE)) {
    228 		return progress;
    229 	}
    230 
    231 	progress = 1;
    232 	if (v & TS102_UCTRL_STS_RXNE_STA) {
    233 		d = tctrl_read_data(sc);
    234 		switch (sc->sc_state) {
    235 		case TCTRL_IDLE:
    236 			if (d == 0xfa) {
    237 				sc->sc_pending |= TCTRL_SEND_RD_EVENT_STATUS;
    238 			} else {
    239 				printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
    240 					sc->sc_dev.dv_xname, sc->sc_op, d);
    241 			}
    242 			goto again;
    243 		case TCTRL_ACK:
    244 			if (d != 0xfe) {
    245 				printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
    246 					sc->sc_dev.dv_xname, sc->sc_op, d);
    247 			}
    248 #if 0
    249 			printf(" ack=0x%02x", d);
    250 #endif
    251 			sc->sc_rsplen--;
    252 			sc->sc_rspoff = 0;
    253 			sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
    254 #if 0
    255 			if (sc->sc_rsplen > 0) {
    256 				printf(" [data(%u)]", sc->sc_rsplen);
    257 			} else {
    258 				printf(" [idle]\n");
    259 			}
    260 #endif
    261 			goto again;
    262 		case TCTRL_DATA:
    263 			sc->sc_rspbuf[sc->sc_rspoff++] = d;
    264 #if 0
    265 			printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
    266 #endif
    267 			if (sc->sc_rspoff == sc->sc_rsplen) {
    268 #if 0
    269 				printf(" [idle]\n");
    270 #endif
    271 				sc->sc_state = TCTRL_IDLE;
    272 				tctrl_process_response(sc);
    273 			}
    274 			goto again;
    275 		default:
    276 			printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
    277 			       sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
    278 			goto again;
    279 		}
    280 	}
    281 	if (sc->sc_state == TCTRL_IDLE) {
    282 		sc->sc_cmdoff = 0;
    283 		sc->sc_cmdlen = 0;
    284 		if (sc->sc_pending & TCTRL_SEND_POWEROFF) {
    285 			sc->sc_pending &= ~TCTRL_SEND_POWEROFF;
    286 			sc->sc_cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
    287 			sc->sc_cmdlen = 1;
    288 			sc->sc_rsplen = 0;
    289 		} else if (sc->sc_pending & TCTRL_SEND_RD_EVENT_STATUS) {
    290 			sc->sc_pending &= ~TCTRL_SEND_RD_EVENT_STATUS;
    291 			sc->sc_cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
    292 			sc->sc_cmdlen = 1;
    293 			sc->sc_rsplen = 3;
    294 		} else if (sc->sc_pending & TCTRL_SEND_RD_EXT_STATUS) {
    295 			sc->sc_pending &= ~TCTRL_SEND_RD_EXT_STATUS;
    296 			sc->sc_cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
    297 			sc->sc_cmdlen = 1;
    298 			sc->sc_rsplen = 3;
    299 		} else if (sc->sc_pending & TCTRL_SEND_BITPORT_NOP) {
    300 			sc->sc_pending &= ~TCTRL_SEND_BITPORT_NOP;
    301 			tctrl_setup_bitport(sc, 1);
    302 		} else if (sc->sc_pending & TCTRL_SEND_BITPORT) {
    303 			sc->sc_pending &= ~TCTRL_SEND_BITPORT;
    304 			tctrl_setup_bitport(sc, 0);
    305 		}
    306 		if (sc->sc_cmdlen > 0) {
    307 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    308 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    309 				|TS102_UCTRL_INT_TXNF_MSK
    310 				|TS102_UCTRL_INT_TXNF_REQ);
    311 			v = tctrl_read(sc, TS102_REG_UCTRL_STS);
    312 		}
    313 	}
    314 	if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
    315 		tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
    316 #if 0
    317 		if (sc->sc_cmdoff == 1) {
    318 			printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
    319 				sc->sc_cmdbuf[0], sc->sc_rsplen);
    320 		} else {
    321 			printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
    322 				sc->sc_cmdbuf[sc->sc_cmdoff-1]);
    323 		}
    324 #endif
    325 		if (sc->sc_cmdoff == sc->sc_cmdlen) {
    326 			sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
    327 #if 0
    328 			printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
    329 #endif
    330 			if (sc->sc_cmdoff == 1) {
    331 				sc->sc_op = sc->sc_cmdbuf[0];
    332 			}
    333 			tctrl_write(sc, TS102_REG_UCTRL_INT,
    334 				tctrl_read(sc, TS102_REG_UCTRL_INT)
    335 				& (~TS102_UCTRL_INT_TXNF_MSK
    336 				   |TS102_UCTRL_INT_TXNF_REQ));
    337 		} else if (sc->sc_state == TCTRL_IDLE) {
    338 			sc->sc_op = sc->sc_cmdbuf[0];
    339 			sc->sc_state = TCTRL_ARGS;
    340 #if 0
    341 			printf(" [args]");
    342 #endif
    343 		}
    344 	}
    345 	goto again;
    346 }
    347 
    348 static void
    349 tctrl_setup_bitport(struct tctrl_softc *sc, int nop)
    350 {
    351 	if (nop) {
    352 		sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT;
    353 		sc->sc_cmdbuf[1] = 0xff;
    354 		sc->sc_cmdbuf[2] = 0;
    355 		sc->sc_cmdlen = 3;
    356 		sc->sc_rsplen = 2;
    357 	} else {
    358 		if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
    359 		    || (!sc->sc_tft_on)) {
    360 			sc->sc_cmdbuf[2] = TS102_BITPORT_TFTPWR;
    361 		} else {
    362 			sc->sc_cmdbuf[2] = 0;
    363 		}
    364 		sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT;
    365 		sc->sc_cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
    366 		sc->sc_cmdlen = 3;
    367 		sc->sc_rsplen = 2;
    368 	}
    369 }
    370 
    371 static void
    372 tctrl_process_response(struct tctrl_softc *sc)
    373 {
    374 	switch (sc->sc_op) {
    375 	case TS102_OP_RD_EXT_STATUS: {
    376 		sc->sc_ext_status = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1];
    377 		break;
    378 	}
    379 	case TS102_OP_RD_EVENT_STATUS: {
    380 		unsigned int v = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1];
    381 		if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
    382 			printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
    383 		}
    384 		if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
    385 			printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    386 		}
    387 		if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
    388 			printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
    389 		}
    390 		if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
    391 			sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
    392 			printf("%s: main power %s\n", sc->sc_dev.dv_xname,
    393 			       (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? "removed" : "restored");
    394 		}
    395 		if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
    396 			sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS;
    397 			sc->sc_pending |= TCTRL_SEND_BITPORT;
    398 #if 0
    399 			printf("%s: lid %s\n", sc->sc_dev.dv_xname,
    400 			       (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? "opened" : "closed");
    401 #endif
    402 		}
    403 		break;
    404 	}
    405 	case TS102_OP_CTL_BITPORT:
    406 		sc->sc_bitport = (sc->sc_rspbuf[0] & sc->sc_cmdbuf[1]) ^ sc->sc_cmdbuf[2];
    407 		break;
    408 	default:
    409 		break;
    410 	}
    411 }
    412 
    413 void
    414 tadpole_powerdown(void)
    415 {
    416 	struct tctrl_softc *sc;
    417 	int i, s;
    418 
    419 	if (tctrl_cd.cd_devs == NULL
    420 	    || tctrl_cd.cd_ndevs == 0
    421 	    || tctrl_cd.cd_devs[0] == NULL) {
    422 		return;
    423 	}
    424 
    425 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0];
    426 	s = splhigh();
    427 	sc->sc_pending |= TCTRL_SEND_POWEROFF;
    428 	for (i = 0; i < 10000; i++) {
    429 		tctrl_intr(sc);
    430 		DELAY(1);
    431 	}
    432 	splx(s);
    433 }
    434 
    435 void
    436 tadpole_set_video(int enabled)
    437 {
    438 	struct tctrl_softc *sc;
    439 	int s;
    440 
    441 	if (tctrl_cd.cd_devs == NULL
    442 	    || tctrl_cd.cd_ndevs == 0
    443 	    || tctrl_cd.cd_devs[0] == NULL) {
    444 		return;
    445 	}
    446 
    447 	sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0];
    448 	s = splhigh();
    449 	if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
    450 		sc->sc_tft_on = enabled;
    451 		if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
    452 			splx(s);
    453 			return;
    454 		}
    455 		sc->sc_pending |= TCTRL_SEND_BITPORT;
    456 		tctrl_intr(sc);
    457 	}
    458 	splx(s);
    459 }
    460 
    461 static void
    462 tctrl_write_data(struct tctrl_softc *sc, u_int8_t v)
    463 {
    464 	unsigned int i;
    465 	for (i = 0; i < 100; i++)  {
    466 		if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    467 			break;
    468 	}
    469 	tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
    470 }
    471 
    472 static u_int8_t
    473 tctrl_read_data(struct tctrl_softc *sc)
    474 {
    475 	unsigned int i, v;
    476 
    477 	for (i = 0; i < 100000; i++) {
    478 		if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
    479 			break;
    480 		DELAY(1);
    481 	}
    482 
    483 	v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
    484 	tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
    485 	return v;
    486 }
    487 
    488 static u_int8_t
    489 tctrl_read(struct tctrl_softc *sc, bus_size_t off)
    490 {
    491 	sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
    492 	return sc->sc_junk;
    493 }
    494 
    495 static void
    496 tctrl_write(struct tctrl_softc *sc, bus_size_t off, u_int8_t v)
    497 {
    498 	sc->sc_junk = v;
    499 	bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
    500 }
    501