PERFORCE change 156942 for review

Andrew Turner andrew at FreeBSD.org
Fri Jan 30 20:25:38 PST 2009


http://perforce.freebsd.org/chv.cgi?CH=156942

Change 156942 by andrew at andrew_bender on 2009/01/31 04:24:57

	Get the S3c24x0 uart driver working on real hardware

Affected files ...

.. //depot/projects/arm/src/sys/arm/s3c2xx0/s3c2xx0reg.h#2 edit
.. //depot/projects/arm/src/sys/arm/s3c2xx0/uart_bus_s3c2410.c#3 edit
.. //depot/projects/arm/src/sys/arm/s3c2xx0/uart_dev_s3c2410.c#7 edit

Differences ...

==== //depot/projects/arm/src/sys/arm/s3c2xx0/s3c2xx0reg.h#2 (text+ko) ====

@@ -103,9 +103,9 @@
 #define	 UTRSTAT_TXEMPTY           (1<<1) /* TX fifo or buffer empty */
 #define	 UTRSTAT_RXREADY	   (1<<0) /* RX fifo or buffer is not empty */
 #define	SSCOM_UERSTAT	0x14	/* Error status register */
-#define	 UERSTAT_BREAK	  (1<<3) /* Break signal */
+#define	 UERSTAT_BREAK	  (1<<3) /* Break signal, not 2410 */
 #define	 UERSTAT_FRAME	  (1<<2) /* Frame error */
-#define	 UERSTAT_PARITY	  (1<<1) /* Parity error */
+#define	 UERSTAT_PARITY	  (1<<1) /* Parity error, not 2410 */
 #define	 UERSTAT_OVERRUN  (1<<0) /* Overrun */
 #define	 UERSTAT_ALL_ERRORS (UERSTAT_OVERRUN|UERSTAT_BREAK|UERSTAT_FRAME|UERSTAT_PARITY)
 #define	SSCOM_UFSTAT	0x18	/* Fifo status register */
@@ -115,6 +115,13 @@
 #define	 UFSTAT_TXCOUNT	  (0x0f<<UFSTAT_TXCOUNT_SHIFT)
 #define	 UFSTAT_RXCOUNT_SHIFT 0		/* RX FIFO count */
 #define	 UFSTAT_RXCOUNT	  (0x0f<<UFSTAT_RXCOUNT_SHIFT)
+#if 0
+/* These are differend on the 244x */
+#define  UFSTAT_TXFULL (1<<14)
+#define  UFSTAT_TXCOUNT_SHIFT 8
+#define  UFSTAT_TXCOUNT (0x3f<<UFSTAT_TXCOUNT_SHIFT)
+#define  UFSTAT_RXCOUNT (0x3f<<UFSTAT_RXCOUNT_SHIFT)
+#endif
 #define	SSCOM_UMSTAT	0x1c	/* Modem status register */
 /*       UMSTAT_DCTS is defined in s3c{2800,24x0}reg.h */
 #define	 UMSTAT_CTS	  (1<<0) /* Clear to send */

==== //depot/projects/arm/src/sys/arm/s3c2xx0/uart_bus_s3c2410.c#3 (text+ko) ====

@@ -11,8 +11,6 @@
 #include <sys/rman.h>
 #include <machine/resource.h>
 
-#include <dev/pci/pcivar.h>
-
 #include <dev/uart/uart.h>
 #include <dev/uart/uart_bus.h>
 #include <dev/uart/uart_cpu.h>

==== //depot/projects/arm/src/sys/arm/s3c2xx0/uart_dev_s3c2410.c#7 (text+ko) ====

@@ -46,6 +46,9 @@
 
 #define      DEFAULT_RCLK    3686400
 
+static int sscomspeed(long, long);
+static int s3c24x0_uart_param(struct uart_bas *, int, int, int, int);
+
 /*
  * Low-level UART interface.
  */
@@ -58,22 +61,7 @@
 
 extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
 
-struct uart_ops uart_s3c2410_ops = {
-	.probe = s3c2410_probe,
-	.init = s3c2410_init,
-	.term = s3c2410_term,
-	.putc = s3c2410_putc,
-	.rxready = s3c2410_rxready,
-	.getc = s3c2410_getc,
-};
-
 static int
-s3c2410_probe(struct uart_bas *bas)
-{
-	return (0);
-}
-
-static int
 sscomspeed(long speed, long frequency)
 {
 #define	divrnd(n, q)	(((n)*2/(q)+1)/2)	/* divide and round off */
@@ -92,22 +80,88 @@
 
 #undef	divrnd
 }
+
+static int
+s3c24x0_uart_param(struct uart_bas *bas, int baudrate, int databits,
+    int stopbits, int parity)
+{
+	int brd, ulcon;
+
+	ulcon = 0;
+
+	switch(databits) {
+	case 5:
+		ulcon |= ULCON_LENGTH_5;
+		break;
+	case 6:
+		ulcon |= ULCON_LENGTH_6;
+		break;
+	case 7:
+		ulcon |= ULCON_LENGTH_7;
+		break;
+	case 8:
+		ulcon |= ULCON_LENGTH_8;
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	switch (parity) {
+	case UART_PARITY_NONE:
+		ulcon |= ULCON_PARITY_NONE;
+		break;
+	case UART_PARITY_ODD:
+		ulcon |= ULCON_PARITY_ODD;
+		break;
+	case UART_PARITY_EVEN:
+		ulcon |= ULCON_PARITY_EVEN;
+		break;
+	case UART_PARITY_MARK:
+	case UART_PARITY_SPACE:
+	default:
+		return (EINVAL);
+	}
+
+	if (stopbits == 2)
+		ulcon |= ULCON_STOP;
+
+	uart_setreg(bas, SSCOM_ULCON, ulcon);
+
+	brd = sscomspeed(baudrate, bas->rclk);
+	uart_setreg(bas, SSCOM_UBRDIV, brd);
+
+	return (0);
+}
+
+struct uart_ops uart_s3c2410_ops = {
+	.probe = s3c2410_probe,
+	.init = s3c2410_init,
+	.term = s3c2410_term,
+	.putc = s3c2410_putc,
+	.rxready = s3c2410_rxready,
+	.getc = s3c2410_getc,
+};
+
+static int
+s3c2410_probe(struct uart_bas *bas)
+{
+	return (0);
+}
+
 static void
 s3c2410_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
     int parity)
 {
-	int brd;
-
 	if (bas->rclk == 0)
 		bas->rclk = DEFAULT_RCLK;
-	uart_setreg(bas, SSCOM_ULCON, 0x23);
+
 	uart_setreg(bas, SSCOM_UCON, 0);
 	uart_setreg(bas, SSCOM_UFCON,
 	    UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
 	    UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
 	    UFCON_FIFO_ENABLE);
-	brd = sscomspeed(baudrate, bas->rclk);
-	uart_setreg(bas, SSCOM_UBRDIV, brd);
+	s3c24x0_uart_param(bas, baudrate, databits, stopbits, parity);
+
 	/* Enable UART. */
 	uart_setreg(bas, SSCOM_UCON, UCON_TXMODE_INT|UCON_RXMODE_INT|UCON_TOINT);
 	uart_setreg(bas, SSCOM_UMCON, UMCON_RTS);
@@ -122,9 +176,9 @@
 static void
 s3c2410_putc(struct uart_bas *bas, int c)
 {
-#if 0
-	while (uart_getreg(bas, SSCOM_UFSTAT) & UFSTAT_TXFULL);
-#endif
+	while (!(uart_getreg(bas, SSCOM_UTRSTAT) & UTRSTAT_TXEMPTY))
+		continue;
+
 	uart_setreg(bas, SSCOM_UTXH, c);
 }
 
@@ -138,11 +192,10 @@
 static int
 s3c2410_getc(struct uart_bas *bas, struct mtx *mtx)
 {
-	int c;
+	while (!sscom_rxrdy(bas->bst, bas->bsh))
+		continue;
 
-	while (!sscom_rxrdy(bas->bst, bas->bsh));
 	return sscom_getc(bas->bst, bas->bsh);
-	return (c);
 }
 
 static int s3c2410_bus_probe(struct uart_softc *sc);
@@ -180,29 +233,39 @@
 static int
 s3c2410_bus_attach(struct uart_softc *sc)
 {
-	 bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+	bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
 
-	 sc->sc_txfifosz = 3;
-	 sc->sc_rxfifosz = 1;
-	 sc->sc_hwiflow = 0;
+	/*
+	 * TODO: The S3C2410 has a 16 byte fifo, the s3c2440 has a
+	 * 64 byte fifo. figure out which CPU we are on to set this
+	 */
+	sc->sc_txfifosz = 16;
+	sc->sc_rxfifosz = 16;
+	sc->sc_hwiflow = 0;
+	sc->sc_hwoflow = 0;
 	return (0);
 }
+
 static int
 s3c2410_bus_transmit(struct uart_softc *sc)
 {
-	sc->sc_txbusy = 1;
+	uart_lock(sc->sc_hwmtx);
 	for (int i = 0; i < sc->sc_txdatasz; i++) {
 		s3c2410_putc(&sc->sc_bas, sc->sc_txbuf[i]);
 		uart_barrier(&sc->sc_bas);
 	}
+	sc->sc_txbusy = 1;
+	uart_unlock(sc->sc_hwmtx);
 
 	return (0);
 }
+
 static int
 s3c2410_bus_setsig(struct uart_softc *sc, int sig)
 {
 	return (0);
 }
+
 static int
 s3c2410_bus_receive(struct uart_softc *sc)
 {
@@ -210,30 +273,41 @@
 	uart_rx_put(sc, uart_getreg(&sc->sc_bas, SSCOM_URXH));
 	return (0);
 }
+
 static int
 s3c2410_bus_param(struct uart_softc *sc, int baudrate, int databits,
     int stopbits, int parity)
 {
-	
-	return (0);
+	int error;
+
+	uart_lock(sc->sc_hwmtx);
+	error = s3c24x0_uart_param(&sc->sc_bas, baudrate, databits, stopbits,
+	    parity);
+	uart_unlock(sc->sc_hwmtx);
+
+	return (error);
 }
+
 static int
 s3c2410_bus_ipend(struct uart_softc *sc)
 {
+	uint32_t utrstat;
 	int ipend = 0;
-	int sr;
 
-	sr = uart_getreg(&sc->sc_bas, SSCOM_UFSTAT);
+	uart_lock(sc->sc_hwmtx);
+	utrstat = uart_getreg(&sc->sc_bas, SSCOM_UTRSTAT);
+	uart_unlock(sc->sc_hwmtx);
 
-	if ((sr & UFSTAT_TXCOUNT) == 0 && sc->sc_txbusy) {
+	if ((utrstat & UTRSTAT_TXEMPTY) == UTRSTAT_TXEMPTY) {
 		ipend |= SER_INT_TXIDLE;
 	}
-	if ((sr & UFSTAT_RXCOUNT) != 0) {
+	if ((utrstat & UTRSTAT_RXREADY) == UTRSTAT_RXREADY) {
 		ipend |= SER_INT_RXREADY;
 	}
 
 	return (ipend);
 }
+
 static int
 s3c2410_bus_flush(struct uart_softc *sc, int what)
 {
@@ -257,5 +331,5 @@
 	1,
 	.uc_ops = &uart_s3c2410_ops,
 	.uc_range = 8,
-	.uc_rclk = 3686400
+	.uc_rclk = DEFAULT_RCLK
 };


More information about the p4-projects mailing list