diff options
| author | 1999-09-07 02:58:49 +0000 | |
|---|---|---|
| committer | 1999-09-07 02:58:49 +0000 | |
| commit | 9d17c5f08eecc7337f649827d995a777d8dbb21d (patch) | |
| tree | 46a09ad5afe79fa85cf7e9b9e9d2001cc0c36d9d /sys/arch/sparc/dev/tctrl.c | |
| parent | succesfully -> successfully (diff) | |
| download | wireguard-openbsd-9d17c5f08eecc7337f649827d995a777d8dbb21d.tar.xz wireguard-openbsd-9d17c5f08eecc7337f649827d995a777d8dbb21d.zip | |
add tadpole microcontroller device driver; from NetBSD
power the tft down on screenblank
Diffstat (limited to 'sys/arch/sparc/dev/tctrl.c')
| -rw-r--r-- | sys/arch/sparc/dev/tctrl.c | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/sys/arch/sparc/dev/tctrl.c b/sys/arch/sparc/dev/tctrl.c new file mode 100644 index 00000000000..b3a924d2095 --- /dev/null +++ b/sys/arch/sparc/dev/tctrl.c @@ -0,0 +1,499 @@ +/* $OpenBSD: tctrl.c,v 1.1 1999/09/07 02:58:50 jason Exp $ */ +/* $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $ */ + +/*- + * Copyright (c) 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/tty.h> +#include <sys/proc.h> +#include <sys/user.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/types.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include <sparc/dev/ts102reg.h> +#include <sparc/dev/tctrlvar.h> + +const char *tctrl_ext_statuses[16] = { + "main power available", + "internal battery attached", + "external battery attached", + "external VGA attached", + "external keyboard attached", + "external mouse attached", + "lid down", + "internal battery charging", + "external battery charging", + "internal battery discharging", + "external battery discharging", +}; + +struct tctrl_softc { + struct device sc_dev; + struct uctrl_regs *sc_regs; + struct intrhand sc_ih; + int sc_node; + unsigned int sc_junk; + unsigned int sc_ext_status; + unsigned int sc_pending; +#define TCTRL_SEND_BITPORT 0x0001 +#define TCTRL_SEND_POWEROFF 0x0002 +#define TCTRL_SEND_RD_EXT_STATUS 0x0004 +#define TCTRL_SEND_RD_EVENT_STATUS 0x0008 +#define TCTRL_SEND_BITPORT_NOP 0x0010 + enum { TCTRL_IDLE, TCTRL_ARGS, + TCTRL_ACK, TCTRL_DATA } sc_state; + u_int8_t sc_cmdbuf[16]; + u_int8_t sc_rspbuf[16]; + u_int8_t sc_bitport; + u_int8_t sc_tft_on; + u_int8_t sc_op; + u_int8_t sc_cmdoff; + u_int8_t sc_cmdlen; + u_int8_t sc_rspoff; + u_int8_t sc_rsplen; + + struct evcnt sc_intrcnt; /* interrupt counting */ +}; + +int tctrl_match __P((struct device *, void *, void *)); +void tctrl_attach __P((struct device *, struct device *, void *)); + +void tctrl_write_data __P((struct tctrl_softc *, u_int8_t)); +u_int8_t tctrl_read_data __P((struct tctrl_softc *)); +int tctrl_intr __P((void *)); +void tctrl_setup_bitport __P((struct tctrl_softc *, int)); +void tctrl_process_response __P((struct tctrl_softc *)); + +struct cfattach tctrl_ca = { + sizeof(struct tctrl_softc), tctrl_match, tctrl_attach +}; + +struct cfdriver tctrl_cd = { + NULL, "tctrl", DV_DULL +}; + +int +tctrl_match(parent, vcf, aux) + struct device *parent; + void *vcf; + void *aux; +{ + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + /* + * Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller + * (who's interface is off the TS102 PCMCIA controller but there + * exists a OpenProm for microcontroller interface). + */ + if (strcmp("uctrl", ra->ra_name)) + return (0); + + return (1); +} + +void +tctrl_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct confargs *ca = aux; + struct tctrl_softc *sc = (void *)self; + int pri; + unsigned int i, v; + + /* + * We're living on a sbus slot that looks like an obio that + * looks like an sbus slot. + */ + if (ca->ca_ra.ra_nintr != 1) { + printf(": expected 1 interrupt, got %d\n", + ca->ca_ra.ra_nintr); + return; + } + pri = ca->ca_ra.ra_intr[0].int_pri; + + if (ca->ca_ra.ra_nreg != 1) { + printf(": expected 1 register, got %d\n", + ca->ca_ra.ra_nreg); + return; + } + sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0, + ca->ca_ra.ra_reg[0].rr_len); + + sc->sc_node = ca->ca_ra.ra_node; + + printf("\n"); + + sc->sc_tft_on = 1; + + /* clear any pending data. + */ + for (i = 0; i < 10000; i++) { + if ((TS102_UCTRL_STS_RXNE_STA & sc->sc_regs->stat) == 0) + break; + v = sc->sc_regs->data; + sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA; + } + + sc->sc_ih.ih_fun = tctrl_intr; + sc->sc_ih.ih_arg = sc; + intr_establish(pri, &sc->sc_ih); + evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); + + /* See what the external status is + */ + sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; + do { + tctrl_intr(sc); + } while (sc->sc_state != TCTRL_IDLE); + + if (sc->sc_ext_status != 0) { + const char *sep; + + printf("%s: ", sc->sc_dev.dv_xname); + v = sc->sc_ext_status; + for (i = 0, sep = ""; v != 0; i++, v >>= 1) { + if (v & 1) { + printf("%s%s", sep, tctrl_ext_statuses[i]); + sep = ", "; + } + } + printf("\n"); + } + + /* Get a current of the control bitport; + */ + sc->sc_pending |= TCTRL_SEND_BITPORT_NOP; + do { + tctrl_intr(sc); + } while (sc->sc_state != TCTRL_IDLE); + + sc->sc_regs->intr = TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK; +} + +int +tctrl_intr(void *arg) +{ + struct tctrl_softc *sc = arg; + unsigned int v, d; + int progress = 0; + + again: + /* find out the cause(s) of the interrupt */ + v = sc->sc_regs->stat; + + /* clear the cause(s) of the interrupt */ + sc->sc_regs->stat = v; + + v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA); + if (sc->sc_cmdoff >= sc->sc_cmdlen) { + v &= ~TS102_UCTRL_STS_TXNF_STA; + } + if ((v == 0) && (sc->sc_pending == 0 || sc->sc_state != TCTRL_IDLE)) { + return (progress); + } + + progress = 1; + if (v & TS102_UCTRL_STS_RXNE_STA) { + d = tctrl_read_data(sc); + switch (sc->sc_state) { + case TCTRL_IDLE: + if (d == 0xfa) { + sc->sc_pending |= TCTRL_SEND_RD_EVENT_STATUS; + } else { + printf("%s: (op=0x%02x): unexpected data (0x%02x)\n", + sc->sc_dev.dv_xname, sc->sc_op, d); + } + goto again; + case TCTRL_ACK: + if (d != 0xfe) { + printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n", + sc->sc_dev.dv_xname, sc->sc_op, d); + } +#if 0 + printf(" ack=0x%02x", d); +#endif + sc->sc_rsplen--; + sc->sc_rspoff = 0; + sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE; +#if 0 + if (sc->sc_rsplen > 0) { + printf(" [data(%u)]", sc->sc_rsplen); + } else { + printf(" [idle]\n"); + } +#endif + goto again; + case TCTRL_DATA: + sc->sc_rspbuf[sc->sc_rspoff++] = d; +#if 0 + printf(" [%d]=0x%02x", sc->sc_rspoff-1, d); +#endif + if (sc->sc_rspoff == sc->sc_rsplen) { +#if 0 + printf(" [idle]\n"); +#endif + sc->sc_state = TCTRL_IDLE; + tctrl_process_response(sc); + } + goto again; + default: + printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n", + sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state); + goto again; + } + } + if (sc->sc_state == TCTRL_IDLE) { + sc->sc_cmdoff = 0; + sc->sc_cmdlen = 0; + if (sc->sc_pending & TCTRL_SEND_POWEROFF) { + sc->sc_pending &= ~TCTRL_SEND_POWEROFF; + sc->sc_cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF; + sc->sc_cmdlen = 1; + sc->sc_rsplen = 0; + } else if (sc->sc_pending & TCTRL_SEND_RD_EVENT_STATUS) { + sc->sc_pending &= ~TCTRL_SEND_RD_EVENT_STATUS; + sc->sc_cmdbuf[0] = TS102_OP_RD_EVENT_STATUS; + sc->sc_cmdlen = 1; + sc->sc_rsplen = 3; + } else if (sc->sc_pending & TCTRL_SEND_RD_EXT_STATUS) { + sc->sc_pending &= ~TCTRL_SEND_RD_EXT_STATUS; + sc->sc_cmdbuf[0] = TS102_OP_RD_EXT_STATUS; + sc->sc_cmdlen = 1; + sc->sc_rsplen = 3; + } else if (sc->sc_pending & TCTRL_SEND_BITPORT_NOP) { + sc->sc_pending &= ~TCTRL_SEND_BITPORT_NOP; + tctrl_setup_bitport(sc, 1); + } else if (sc->sc_pending & TCTRL_SEND_BITPORT) { + sc->sc_pending &= ~TCTRL_SEND_BITPORT; + tctrl_setup_bitport(sc, 0); + } + if (sc->sc_cmdlen > 0) { + sc->sc_regs->intr = + sc->sc_regs->intr | TS102_UCTRL_INT_TXNF_MSK + |TS102_UCTRL_INT_TXNF_REQ; + v = sc->sc_regs->stat; + } + } + if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) { + tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]); +#if 0 + if (sc->sc_cmdoff == 1) { + printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname, + sc->sc_cmdbuf[0], sc->sc_rsplen); + } else { + printf(" [%d]=0x%02x", sc->sc_cmdoff-1, + sc->sc_cmdbuf[sc->sc_cmdoff-1]); + } +#endif + if (sc->sc_cmdoff == sc->sc_cmdlen) { + sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE; +#if 0 + printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n"); +#endif + if (sc->sc_cmdoff == 1) { + sc->sc_op = sc->sc_cmdbuf[0]; + } + sc->sc_regs->intr = + sc->sc_regs->intr & (~TS102_UCTRL_INT_TXNF_MSK + |TS102_UCTRL_INT_TXNF_REQ); + } else if (sc->sc_state == TCTRL_IDLE) { + sc->sc_op = sc->sc_cmdbuf[0]; + sc->sc_state = TCTRL_ARGS; +#if 0 + printf(" [args]"); +#endif + } + } + goto again; +} + +void +tctrl_setup_bitport(struct tctrl_softc *sc, int nop) +{ + if (nop) { + sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT; + sc->sc_cmdbuf[1] = 0xff; + sc->sc_cmdbuf[2] = 0; + sc->sc_cmdlen = 3; + sc->sc_rsplen = 2; + } else { + if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) + || (!sc->sc_tft_on)) { + sc->sc_cmdbuf[2] = TS102_BITPORT_TFTPWR; + } else { + sc->sc_cmdbuf[2] = 0; + } + sc->sc_cmdbuf[0] = TS102_OP_CTL_BITPORT; + sc->sc_cmdbuf[1] = ~TS102_BITPORT_TFTPWR; + sc->sc_cmdlen = 3; + sc->sc_rsplen = 2; + } +} + +void +tctrl_process_response(struct tctrl_softc *sc) +{ + switch (sc->sc_op) { + case TS102_OP_RD_EXT_STATUS: { + sc->sc_ext_status = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1]; + break; + } + case TS102_OP_RD_EVENT_STATUS: { + unsigned int v = sc->sc_rspbuf[0] * 256 + sc->sc_rspbuf[1]; + if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) { + printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname); + } + if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) { + printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname); + } + if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) { + printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname); + } + if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) { + sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; + printf("%s: main power %s\n", sc->sc_dev.dv_xname, + (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ? "removed" : "restored"); + } + if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) { + sc->sc_pending |= TCTRL_SEND_RD_EXT_STATUS; + sc->sc_pending |= TCTRL_SEND_BITPORT; +#if 0 + printf("%s: lid %s\n", sc->sc_dev.dv_xname, + (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ? "opened" : "closed"); +#endif + } + break; + } + case TS102_OP_CTL_BITPORT: + sc->sc_bitport = (sc->sc_rspbuf[0] & sc->sc_cmdbuf[1]) ^ sc->sc_cmdbuf[2]; + break; + default: + break; + } +} + +void +tadpole_powerdown(void) +{ + struct tctrl_softc *sc; + int i, s; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return; + } + + sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0]; + s = splhigh(); + sc->sc_pending |= TCTRL_SEND_POWEROFF; + for (i = 0; i < 10000; i++) { + tctrl_intr(sc); + DELAY(1); + } + splx(s); +} + +void +tadpole_set_video(int enabled) +{ + struct tctrl_softc *sc; + int s; + + if (tctrl_cd.cd_devs == NULL + || tctrl_cd.cd_ndevs == 0 + || tctrl_cd.cd_devs[0] == NULL) { + return; + } + + sc = (struct tctrl_softc *) tctrl_cd.cd_devs[0]; + s = splhigh(); + if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) { + sc->sc_tft_on = enabled; + if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) { + splx(s); + return; + } + sc->sc_pending |= TCTRL_SEND_BITPORT; + tctrl_intr(sc); + } + splx(s); +} + +void +tctrl_write_data(sc, v) + struct tctrl_softc *sc; + u_int8_t v; +{ + unsigned int i; + + for (i = 0; i < 100; i++) { + if (sc->sc_regs->stat & TS102_UCTRL_STS_TXNF_STA) + break; + } + sc->sc_regs->data = v; +} + +u_int8_t +tctrl_read_data(sc) + struct tctrl_softc *sc; +{ + unsigned int i, v; + + for (i = 0; i < 100000; i++) { + if (sc->sc_regs->stat & TS102_UCTRL_STS_RXNE_STA) + break; + DELAY(1); + } + + v = sc->sc_regs->data; + sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA; + return v; +} |
