diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2005-10-13 14:58:57 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2005-10-13 14:58:57 +0000 |
commit | 35182740a9b22fcb144291823d0d222d79d36116 (patch) | |
tree | 73f59c3cbcc1b44f5610b098e95d9e94259de682 /sys | |
parent | f057276ebbf760c0f72a5b8d911a73c13b2f2fe3 (diff) |
Over the years, different UARTs have appeared in the market.
Unfortunately most vendors implement hidden bits/features and ships with
buggy buffers. This is our first attempt to fix this. Test the fifo size
by putting the fifo into loopback mode and reading back what we wrote.
It seems to be very much accurate and has correctly identified several
buggy UARTs. Commented out for now.
Tested by several people with different hardware, many thanks.
Idea from Theo, code by myself.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/com_subr.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/sys/dev/ic/com_subr.c b/sys/dev/ic/com_subr.c index a00a5e99780..40025dabfd8 100644 --- a/sys/dev/ic/com_subr.c +++ b/sys/dev/ic/com_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: com_subr.c,v 1.2 2005/10/13 01:59:42 fgsch Exp $ */ +/* $OpenBSD: com_subr.c,v 1.3 2005/10/13 14:58:56 fgsch Exp $ */ /* * Copyright (c) 1997 - 1999, Jason Downs. All rights reserved. @@ -108,6 +108,7 @@ cdev_decl(com); #endif void com_enable_debugport(struct com_softc *); +void com_fifo_probe(struct com_softc *); #if defined(COM_CONSOLE) || defined(KGDB) void @@ -314,6 +315,10 @@ com_attach_subr(sc) if (sc->sc_fifolen == 0) sc->sc_fifolen = 1; /* default */ +#ifdef notyet + com_fifo_probe(sc); +#endif + /* 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); @@ -376,3 +381,61 @@ com_attach_subr(sc) 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; + } +} |