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
[EMAIL PROTECTED]
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);
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"