Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 May 2006 13:12:29 +1000
From:      Benno Rice <benno@FreeBSD.org>
To:        hackers@FreeBSD.org
Subject:   RFC: Minor changes to uart(4)'s ns8250/ns16550 support.
Message-ID:  <4462AB9D.4000107@FreeBSD.org>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------040608010607010107080407
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

I've made a couple of changes to uart(4)'s support for 
ns8250/ns16550-alikes to support some work I'm doing on porting FreeBSD 
to Intel's XScale PXA255.  The changes are:

- Stop using uart_{get,set}dreg to handle the DL register.  The DL 
register is 16 bits wide, but when the register offset is anything other 
than 0, it's true nature as two individual 8-bit registers is revealed 
and bus_space_{read,write}_2 won't work anymore.  Instead, treat it as 
two single 8-bit registers.

- The PXA255 uses the upper four bits of the IER to handle some of it's 
own configuration for the UART, including the bit that turns the UART on 
and off.  Therefore we can't assume that those bits will be 0, or that 
writing 0 to them is safe.  Instead, always read the IER, make the 
changes and write it back out again.

A patch is attached which contains these changes.  I've already run 
these past marcel and he's ok with them.  If anyone using uart(4) to 
drive one of these parts could test this and let me know if they run 
into any problems, that'd rock.

Many thanks!

-- 
Benno Rice
benno@FreeBSD.org

--------------040608010607010107080407
Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0";
	name="uart-pxa.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="uart-pxa.diff"

Index: sys/dev/ic/ns16550.h
===================================================================
RCS file: /home/ncvs/src/sys/dev/ic/ns16550.h,v
retrieving revision 1.16
diff -u -r1.16 ns16550.h
--- sys/dev/ic/ns16550.h	20 Nov 2004 23:19:42 -0000	1.16
+++ sys/dev/ic/ns16550.h	11 May 2006 03:09:35 -0000
@@ -127,7 +127,8 @@
 #define	com_dlbl	com_dll
 #define	com_dlm		1	/* divisor latch high (R/W) */
 #define	com_dlbh	com_dlm
-#define	REG_DL		com_dll
+#define	REG_DLL		com_dll
+#define	REG_DLH		com_dlm
 
 /* 16450 register #7.  Not multiplexed. */
 #define	com_scr		7	/* scratch register (R/W) */
Index: sys/dev/uart/uart_dev_ns8250.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/uart/uart_dev_ns8250.c,v
retrieving revision 1.21
diff -u -r1.21 uart_dev_ns8250.c
--- sys/dev/uart/uart_dev_ns8250.c	27 Apr 2006 05:43:10 -0000	1.21
+++ sys/dev/uart/uart_dev_ns8250.c	11 May 2006 03:09:49 -0000
@@ -75,7 +75,7 @@
 	lcr = uart_getreg(bas, REG_LCR);
 	uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
 	uart_barrier(bas);
-	divisor = uart_getdreg(bas, REG_DL);
+	divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8);
 	uart_barrier(bas);
 	uart_setreg(bas, REG_LCR, lcr);
 	uart_barrier(bas);
@@ -199,7 +199,8 @@
 			return (EINVAL);
 		uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
 		uart_barrier(bas);
-		uart_setdreg(bas, REG_DL, divisor);
+		uart_setreg(bas, REG_DLL, divisor & 0xff);
+		uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff);
 		uart_barrier(bas);
 	}
 
@@ -245,32 +246,22 @@
 	uart_setreg(bas, REG_LCR, lcr & ~LCR_DLAB);
 	uart_barrier(bas);
 
-	/* Check known 0 bits that depend on !DLAB. */
-	val = uart_getreg(bas, REG_IER);
-	if (val & 0xf0)
-		goto fail;
-
-	uart_setreg(bas, REG_LCR, lcr);
-	uart_barrier(bas);
 	return (0);
-
- fail:
-	uart_setreg(bas, REG_LCR, lcr);
-	uart_barrier(bas);
-	return (ENXIO);
 }
 
 static void
 ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
     int parity)
 {
+	u_char	ier;
 
 	if (bas->rclk == 0)
 		bas->rclk = DEFAULT_RCLK;
 	ns8250_param(bas, baudrate, databits, stopbits, parity);
 
 	/* Disable all interrupt sources. */
-	uart_setreg(bas, REG_IER, 0);
+	ier = uart_getreg(bas, REG_IER) & 0xf0;
+	uart_setreg(bas, REG_IER, ier);
 	uart_barrier(bas);
 
 	/* Disable the FIFO (if present). */
@@ -416,7 +407,8 @@
 	ns8250_bus_getsig(sc);
 
 	ns8250_clrint(bas);
-	ns8250->ier = IER_EMSC | IER_ERLS | IER_ERXRDY;
+	ns8250->ier = uart_getreg(bas, REG_IER) & 0xf0;
+	ns8250->ier |= IER_EMSC | IER_ERLS | IER_ERXRDY;
 	uart_setreg(bas, REG_IER, ns8250->ier);
 	uart_barrier(bas);
 	return (0);
@@ -426,9 +418,11 @@
 ns8250_bus_detach(struct uart_softc *sc)
 {
 	struct uart_bas *bas;
+	u_char ier;
 
 	bas = &sc->sc_bas;
-	uart_setreg(bas, REG_IER, 0);
+	ier = uart_getreg(bas, REG_IER) & 0xf0;
+	uart_setreg(bas, REG_IER, ier);
 	uart_barrier(bas);
 	ns8250_clrint(bas);
 	return (0);
@@ -529,7 +523,8 @@
 		lcr = uart_getreg(bas, REG_LCR);
 		uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
 		uart_barrier(bas);
-		divisor = uart_getdreg(bas, REG_DL);
+		divisor = uart_getreg(bas, REG_DLL) |
+		    (uart_getreg(bas, REG_DLH) << 8);
 		uart_barrier(bas);
 		uart_setreg(bas, REG_LCR, lcr);
 		uart_barrier(bas);
@@ -600,7 +595,7 @@
 {
 	struct uart_bas *bas;
 	int count, delay, error, limit;
-	uint8_t lsr, mcr;
+	uint8_t lsr, mcr, ier;
 
 	bas = &sc->sc_bas;
 
@@ -684,7 +679,8 @@
 		    --limit)
 			DELAY(delay);
 		if (limit == 0) {
-			uart_setreg(bas, REG_IER, 0);
+			ier = uart_getreg(bas, REG_IER) & 0xf0;
+			uart_setreg(bas, REG_IER, ier);
 			uart_setreg(bas, REG_MCR, mcr);
 			uart_setreg(bas, REG_FCR, 0);
 			uart_barrier(bas);

--------------040608010607010107080407--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4462AB9D.4000107>