summaryrefslogtreecommitdiffstats
path: root/sys/dev/uart/uart_dev_ns8250.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/uart/uart_dev_ns8250.c')
-rw-r--r--sys/dev/uart/uart_dev_ns8250.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index 31b1aba..47a61bf 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -649,11 +649,35 @@ int
ns8250_bus_param(struct uart_softc *sc, int baudrate, int databits,
int stopbits, int parity)
{
+ struct ns8250_softc *ns8250;
struct uart_bas *bas;
- int error;
+ int error, limit;
+ ns8250 = (struct ns8250_softc*)sc;
bas = &sc->sc_bas;
uart_lock(sc->sc_hwmtx);
+ /*
+ * When using DW UART with BUSY detection it is necessary to wait
+ * until all serial transfers are finished before manipulating the
+ * line control. LCR will not be affected when UART is busy.
+ */
+ if (ns8250->busy_detect != 0) {
+ /*
+ * Pick an arbitrary high limit to avoid getting stuck in
+ * an infinite loop in case when the hardware is broken.
+ */
+ limit = 10 * 1024;
+ while (((uart_getreg(bas, DW_REG_USR) & USR_BUSY) != 0) &&
+ --limit)
+ DELAY(4);
+
+ if (limit <= 0) {
+ /* UART appears to be stuck */
+ uart_unlock(sc->sc_hwmtx);
+ return (EIO);
+ }
+ }
+
error = ns8250_param(bas, baudrate, databits, stopbits, parity);
uart_unlock(sc->sc_hwmtx);
return (error);
OpenPOWER on IntegriCloud