RFC: Minor changes to uart(4)'s ns8250/ns16550 support.

Benno Rice benno at FreeBSD.org
Thu May 11 03:12:37 UTC 2006


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 at FreeBSD.org
-------------- next part --------------
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);


More information about the freebsd-hackers mailing list