diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-11-23 17:59:01 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-11-23 17:59:01 +0000 |
commit | b90b98975ed5cc9f15b3cf2fd6a394f73d5defb7 (patch) | |
tree | 7f6e4766eb1a8f5b3e0c04c59452b89d00b1b393 /sys/dev/ic/com.c | |
parent | 4c449a40d9a260c0a8f3bf7da4744c5451fb63c0 (diff) |
pccom can finally die; ok kettenis dlg drahn, tested by okan
Diffstat (limited to 'sys/dev/ic/com.c')
-rw-r--r-- | sys/dev/ic/com.c | 352 |
1 files changed, 349 insertions, 3 deletions
diff --git a/sys/dev/ic/com.c b/sys/dev/ic/com.c index 0c5119f5edf..bc0da3fc5ec 100644 --- a/sys/dev/ic/com.c +++ b/sys/dev/ic/com.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com.c,v 1.129 2008/10/15 19:12:19 blambert Exp $ */ +/* $OpenBSD: com.c,v 1.130 2008/11/23 17:59:00 deraadt Exp $ */ /* $NetBSD: com.c,v 1.82.4.1 1996/06/02 09:08:00 mrg Exp $ */ /* @@ -105,7 +105,6 @@ #include <arch/zaurus/dev/zaurus_scoopvar.h> #endif -/* XXX: These belong elsewhere */ cdev_decl(com); static u_char tiocm_xxx2mcr(int); @@ -1338,7 +1337,7 @@ comcnprobe(struct consdev *cp) /* Initialize required fields. */ cp->cn_dev = makedev(commajor, comconsunit); -#if defined(COMCONSOLE) || defined(PCCOMCONSOLE) || !defined(__amd64__) +#if defined(COMCONSOLE) || !defined(__amd64__) cp->cn_pri = CN_HIGHPRI; #else cp->cn_pri = CN_LOWPRI; @@ -1463,4 +1462,351 @@ com_is_console(bus_space_tag_t iot, bus_addr_t iobase) #endif return (0); } +#endif /* COM_PXA2X0 */ + +void com_enable_debugport(struct com_softc *); +void com_fifo_probe(struct com_softc *); + +#if defined(COM_CONSOLE) || defined(KGDB) +void +com_enable_debugport(sc) + struct com_softc *sc; +{ + int s; + + /* Turn on line break interrupt, set carrier. */ + s = splhigh(); +#ifdef KGDB + SET(sc->sc_ier, IER_ERXRDY); +#ifdef COM_PXA2X0 + if (sc->sc_uarttype == COM_UART_PXA2X0) + sc->sc_ier |= IER_EUART | IER_ERXTOUT; +#endif + bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_ier, sc->sc_ier); #endif + SET(sc->sc_mcr, MCR_DTR | MCR_RTS | MCR_IENABLE); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, com_mcr, sc->sc_mcr); + + splx(s); +} +#endif /* COM_CONSOLE || KGDB */ + +void +com_attach_subr(sc) + struct com_softc *sc; +{ + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + u_int8_t lcr; + + sc->sc_ier = 0; +#ifdef COM_PXA2X0 + if (sc->sc_uarttype == COM_UART_PXA2X0) + sc->sc_ier |= IER_EUART; +#endif + /* disable interrupts */ + bus_space_write_1(iot, ioh, com_ier, sc->sc_ier); + +#ifdef COM_CONSOLE + if (sc->sc_iot == comconsiot && sc->sc_iobase == comconsaddr) { + comconsattached = 1; + delay(10000); /* wait for output to finish */ + SET(sc->sc_hwflags, COM_HW_CONSOLE); + SET(sc->sc_swflags, COM_SW_SOFTCAR); + } +#endif + + /* + * Probe for all known forms of UART. + */ + lcr = bus_space_read_1(iot, ioh, com_lcr); + bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); + bus_space_write_1(iot, ioh, com_efr, 0); + bus_space_write_1(iot, ioh, com_lcr, 0); + + bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); + delay(100); + + /* + * Skip specific probes if attachment code knows it already. + */ + if (sc->sc_uarttype == COM_UART_UNKNOWN) + switch (bus_space_read_1(iot, ioh, com_iir) >> 6) { + case 0: + sc->sc_uarttype = COM_UART_16450; + break; + case 2: + sc->sc_uarttype = COM_UART_16550; + break; + case 3: + sc->sc_uarttype = COM_UART_16550A; + break; + default: + sc->sc_uarttype = COM_UART_UNKNOWN; + break; + } + + if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for ST16650s */ + bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); + if (bus_space_read_1(iot, ioh, com_efr) == 0) { + sc->sc_uarttype = COM_UART_ST16650; + } else { + bus_space_write_1(iot, ioh, com_lcr, LCR_EFR); + if (bus_space_read_1(iot, ioh, com_efr) == 0) + sc->sc_uarttype = COM_UART_ST16650V2; + } + } + +#if 0 /* until com works with large FIFOs */ + if (sc->sc_uarttype == COM_UART_ST16650V2) { /* Probe for XR16850s */ + u_int8_t dlbl, dlbh; + + /* Enable latch access and get the current values. */ + bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); + dlbl = bus_space_read_1(iot, ioh, com_dlbl); + dlbh = bus_space_read_1(iot, ioh, com_dlbh); + + /* Zero out the latch divisors */ + bus_space_write_1(iot, ioh, com_dlbl, 0); + bus_space_write_1(iot, ioh, com_dlbh, 0); + + if (bus_space_read_1(iot, ioh, com_dlbh) == 0x10) { + sc->sc_uarttype = COM_UART_XR16850; + sc->sc_uartrev = bus_space_read_1(iot, ioh, com_dlbl); + } + + /* Reset to original. */ + bus_space_write_1(iot, ioh, com_dlbl, dlbl); + bus_space_write_1(iot, ioh, com_dlbh, dlbh); + } +#endif + + if (sc->sc_uarttype == COM_UART_16550A) { /* Probe for TI16750s */ + bus_space_write_1(iot, ioh, com_lcr, lcr | LCR_DLAB); + bus_space_write_1(iot, ioh, com_fifo, + FIFO_ENABLE | FIFO_ENABLE_64BYTE); + if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 7) { +#if 0 + bus_space_write_1(iot, ioh, com_lcr, 0); + if ((bus_space_read_1(iot, ioh, com_iir) >> 5) == 6) +#endif + sc->sc_uarttype = COM_UART_TI16750; + } + bus_space_write_1(iot, ioh, com_fifo, FIFO_ENABLE); + } + + /* Reset the LCR (latch access is probably enabled). */ + bus_space_write_1(iot, ioh, com_lcr, lcr); + if (sc->sc_uarttype == COM_UART_16450) { /* Probe for 8250 */ + u_int8_t scr0, scr1, scr2; + + scr0 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, 0xa5); + scr1 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, 0x5a); + scr2 = bus_space_read_1(iot, ioh, com_scratch); + bus_space_write_1(iot, ioh, com_scratch, scr0); + + if ((scr1 != 0xa5) || (scr2 != 0x5a)) + sc->sc_uarttype = COM_UART_8250; + } + + /* + * Print UART type and initialize ourself. + */ + switch (sc->sc_uarttype) { + case COM_UART_UNKNOWN: + printf(": unknown uart\n"); + break; + case COM_UART_8250: + printf(": ns8250, no fifo\n"); + break; + case COM_UART_16450: + printf(": ns16450, no fifo\n"); + break; + case COM_UART_16550: + printf(": ns16550, no working fifo\n"); + break; + case COM_UART_16550A: + if (sc->sc_fifolen == 0) + sc->sc_fifolen = 16; + printf(": ns16550a, %d byte fifo\n", sc->sc_fifolen); + SET(sc->sc_hwflags, COM_HW_FIFO); + break; +#ifdef COM_PXA2X0 + case COM_UART_PXA2X0: + printf(": pxa2x0, 32 byte fifo"); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 32; + if (sc->sc_iobase == comsiraddr) { + SET(sc->sc_hwflags, COM_HW_SIR); + printf(" (SIR)"); + } + printf("\n"); + break; +#endif + case COM_UART_ST16650: + printf(": st16650, no working fifo\n"); + break; + case COM_UART_ST16650V2: + if (sc->sc_fifolen == 0) + sc->sc_fifolen = 32; + printf(": st16650, %d byte fifo\n", sc->sc_fifolen); + SET(sc->sc_hwflags, COM_HW_FIFO); + break; + case COM_UART_ST16C654: + printf(": st16c654, 64 byte fifo\n"); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 64; + break; + case COM_UART_TI16750: + printf(": ti16750, 64 byte fifo\n"); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 64; + break; +#if 0 + case COM_UART_XR16850: + printf(": xr16850 (rev %d), 128 byte fifo\n", sc->sc_uartrev); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 128; + break; +#ifdef COM_UART_OX16C950 + case COM_UART_OX16C950: + printf(": ox16c950 (rev %d), 128 byte fifo\n", sc->sc_uartrev); + SET(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 128; + break; +#endif +#endif + default: + panic("comattach: bad fifo type"); + } + +#ifdef KGDB + /* + * Allow kgdb to "take over" this port. If this is + * the kgdb device, it has exclusive use. + */ + + if (iot == com_kgdb_iot && sc->sc_iobase == com_kgdb_addr && + !ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { + printf("%s: kgdb\n", sc->sc_dev.dv_xname); + SET(sc->sc_hwflags, COM_HW_KGDB); + } +#endif /* KGDB */ + +#if defined(COM_CONSOLE) || defined(KGDB) + if (!ISSET(sc->sc_hwflags, COM_HW_CONSOLE|COM_HW_KGDB)) +#endif + com_fifo_probe(sc); + + if (sc->sc_fifolen == 0) { + CLR(sc->sc_hwflags, COM_HW_FIFO); + sc->sc_fifolen = 1; + } + + /* clear and disable fifo */ + bus_space_write_1(iot, ioh, com_fifo, FIFO_RCV_RST | FIFO_XMT_RST); + (void)bus_space_read_1(iot, ioh, com_data); + bus_space_write_1(iot, ioh, com_fifo, 0); + + sc->sc_mcr = 0; + bus_space_write_1(iot, ioh, com_mcr, sc->sc_mcr); + +#ifdef COM_CONSOLE + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { + int maj; + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == comopen) + break; + + if (maj < nchrdev && cn_tab->cn_dev == NODEV) + cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); + + printf("%s: console\n", sc->sc_dev.dv_xname); + } +#endif + + timeout_set(&sc->sc_diag_tmo, comdiag, sc); + timeout_set(&sc->sc_dtr_tmo, com_raisedtr, sc); +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + sc->sc_si = softintr_establish(IPL_TTY, comsoft, sc); + if (sc->sc_si == NULL) + panic("%s: can't establish soft interrupt", + sc->sc_dev.dv_xname); +#else + timeout_set(&sc->sc_comsoft_tmo, comsoft, sc); +#endif + + /* + * If there are no enable/disable functions, assume the device + * is always enabled. + */ + if (!sc->enable) + sc->enabled = 1; + +#if defined(COM_CONSOLE) || defined(KGDB) + if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE|COM_HW_KGDB)) + com_enable_debugport(sc); +#endif +} + +void +com_fifo_probe(struct com_softc *sc) +{ + bus_space_handle_t ioh = sc->sc_ioh; + bus_space_tag_t iot = sc->sc_iot; + u_int8_t fifo, ier; + int timo, len; + + if (!ISSET(sc->sc_hwflags, COM_HW_FIFO)) + return; + + ier = 0; +#ifdef COM_PXA2X0 + if (sc->sc_uarttype == COM_UART_PXA2X0) + ier |= IER_EUART; +#endif + bus_space_write_1(iot, ioh, com_ier, ier); + bus_space_write_1(iot, ioh, com_lcr, LCR_DLAB); + bus_space_write_1(iot, ioh, com_dlbl, 3); + bus_space_write_1(iot, ioh, com_dlbh, 0); + bus_space_write_1(iot, ioh, com_lcr, LCR_PNONE | LCR_8BITS); + bus_space_write_1(iot, ioh, com_mcr, MCR_LOOPBACK); + + fifo = FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST; + if (sc->sc_uarttype == COM_UART_TI16750) + fifo |= FIFO_ENABLE_64BYTE; + + bus_space_write_1(iot, ioh, com_fifo, fifo); + + for (len = 0; len < 256; len++) { + bus_space_write_1(iot, ioh, com_data, (len + 1)); + timo = 2000; + while (!ISSET(bus_space_read_1(iot, ioh, com_lsr), + LSR_TXRDY) && --timo) + delay(1); + if (!timo) + break; + } + + delay(100); + + for (len = 0; len < 256; len++) { + timo = 2000; + while (!ISSET(bus_space_read_1(iot, ioh, com_lsr), + LSR_RXRDY) && --timo) + delay(1); + if (!timo || bus_space_read_1(iot, ioh, com_data) != (len + 1)) + break; + } + + /* For safety, always use the smaller value. */ + if (sc->sc_fifolen > len) { + printf("%s: probed fifo depth: %d bytes\n", + sc->sc_dev.dv_xname, len); + sc->sc_fifolen = len; + } +} |