Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Oct 2013 21:54:15 +0200
From:      Zbigniew Bodek <zbb@freebsd.org>
To:        freebsd-embedded@freebsd.org
Cc:        freebsd-arm@freebsd.org, freebsd-current@freebsd.org
Subject:   Changes to UART ns8250
Message-ID:  <CALF_Tx=AwVnr0d75-K-yu97iVgmTJC7aaABoix73zHD%2B5eKJnQ@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hello.

I would like to present a patch for ns8250 serial that I would like to
commit in the near future (if there are no objections).

The patch is fixing newest DesignWare UART with busy detection.
During frequency divisors configuration when UART is busy transferring or
receiving data, line control register manipulation will not take effect.
Therefore, we will not set divisor latch access bit and we will corrupt LCR
instead of configuring divisors.
It is necessary to wait until UART finishes all transfers to proceed with
the configuration.

This was detected on Armada XP as UART fails on this issue 100/100 attempts.
The patch was tested by kevlo@ and me and it works on our Armada XP - based
systems.

Please send your comment or remarks if there are any.

Best regards
Zbigniew Bodek

[-- Attachment #2 --]
From b1e47798ae2698f42277f091e841dfb712566304 Mon Sep 17 00:00:00 2001
From: Zbigniew Bodek <zbb@semihalf.com>
Date: Sat, 5 Oct 2013 02:25:23 +0200
Subject: [PATCH 1/3] Wait for DesignWare UART transfers completion before
 accessing line control

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.
In addition, if Divisor Latch Access Bit is being set in order to
modify UART divisors:
1. We will get BUSY interrupt if interrupts are enabled.
2. Because LCR will not be affected the THR and (even worse) IER
   contents will be corrupted. This will lead to console hang.

Tested by:	kevlo
Approved by:	cognet (mentor)
---
 sys/dev/ic/ns16550.h           |  1 +
 sys/dev/uart/uart_dev_ns8250.c | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/sys/dev/ic/ns16550.h b/sys/dev/ic/ns16550.h
index 659f591..33a7dd1 100644
--- a/sys/dev/ic/ns16550.h
+++ b/sys/dev/ic/ns16550.h
@@ -185,6 +185,7 @@
 #define DW_REG_USR	31	/* DesignWare derived Uart Status Reg */
 #define com_usr		39	/* Octeon 16750/16550 Uart Status Reg */
 #define REG_USR		com_usr
+#define USR_BUSY	1	/* Uart Busy. Serial transfer in progress */
 #define USR_TXFIFO_NOTFULL 2    /* Uart TX FIFO Not full */
 
 /* 16950 register #1.  Access enabled by ACR[7].  Also requires !LCR[7]. */
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index 211d113..5c939ce 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -647,11 +647,21 @@ 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;
 
+	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.
+	 */
+	while (ns8250->busy_detect != 0 &&
+	    (uart_getreg(bas, DW_REG_USR) & USR_BUSY) != 0)
+		;
 	error = ns8250_param(bas, baudrate, databits, stopbits, parity);
 	uart_unlock(sc->sc_hwmtx);
 	return (error);
-- 
1.8.4


Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALF_Tx=AwVnr0d75-K-yu97iVgmTJC7aaABoix73zHD%2B5eKJnQ>