Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 May 2015 19:27:05 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r283321 - stable/10/sys/dev/uart
Message-ID:  <201505231927.t4NJR5lE041645@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Sat May 23 19:27:04 2015
New Revision: 283321
URL: https://svnweb.freebsd.org/changeset/base/283321

Log:
  MFC r272399, r272602, r274451, r274452:
  
    Add uart driver for Qualcomm MSM 7000/8000 series chips.
    It is working on IFC6410 board which has Qualcomm Snapdragon SoC.
  
    Use documented compat string for msm uart.
  
    Make PL011 UART to wait on putc only when TX FIFO is full
  
    Make uart_bus_fdt a decendant of ofwbus

Added:
  stable/10/sys/dev/uart/uart_dev_msm.c
     - copied unchanged from r272399, head/sys/dev/uart/uart_dev_msm.c
  stable/10/sys/dev/uart/uart_dev_msm.h
     - copied unchanged from r272399, head/sys/dev/uart/uart_dev_msm.h
Modified:
  stable/10/sys/dev/uart/uart.h
  stable/10/sys/dev/uart/uart_bus_fdt.c
  stable/10/sys/dev/uart/uart_dev_pl011.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/uart/uart.h
==============================================================================
--- stable/10/sys/dev/uart/uart.h	Sat May 23 19:09:04 2015	(r283320)
+++ stable/10/sys/dev/uart/uart.h	Sat May 23 19:27:04 2015	(r283321)
@@ -65,6 +65,7 @@ struct uart_bas {
 struct uart_class;
 
 extern struct uart_class uart_imx_class __attribute__((weak));
+extern struct uart_class uart_msm_class __attribute__((weak));
 extern struct uart_class uart_ns8250_class __attribute__((weak));
 extern struct uart_class uart_quicc_class __attribute__((weak));
 extern struct uart_class uart_s3c2410_class __attribute__((weak));

Modified: stable/10/sys/dev/uart/uart_bus_fdt.c
==============================================================================
--- stable/10/sys/dev/uart/uart_bus_fdt.c	Sat May 23 19:09:04 2015	(r283320)
+++ stable/10/sys/dev/uart/uart_bus_fdt.c	Sat May 23 19:27:04 2015	(r283321)
@@ -84,6 +84,7 @@ static struct ofw_compat_data compat_dat
 	{"fsl,imx21-uart",	(uintptr_t)&uart_imx_class},
 	{"fsl,mvf600-uart",	(uintptr_t)&uart_vybrid_class},
 	{"lpc,uart",		(uintptr_t)&uart_lpc_class},
+	{"qcom,msm-uartdm",	(uintptr_t)&uart_msm_class},
 	{"ti,ns16550",		(uintptr_t)&uart_ti8250_class},
 	{"ns16550",		(uintptr_t)&uart_ns8250_class},
 	{NULL,			(uintptr_t)NULL},
@@ -156,3 +157,4 @@ uart_fdt_probe(device_t dev)
 }
 
 DRIVER_MODULE(uart, simplebus, uart_fdt_driver, uart_devclass, 0, 0);
+DRIVER_MODULE(uart, ofwbus, uart_fdt_driver, uart_devclass, 0, 0);

Copied: stable/10/sys/dev/uart/uart_dev_msm.c (from r272399, head/sys/dev/uart/uart_dev_msm.c)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/10/sys/dev/uart/uart_dev_msm.c	Sat May 23 19:27:04 2015	(r283321, copy of r272399, head/sys/dev/uart/uart_dev_msm.c)
@@ -0,0 +1,568 @@
+/*-
+ * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Qualcomm MSM7K/8K uart driver */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kdb.h>
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_dev_msm.h>
+
+#include "uart_if.h"
+
+#define	DEF_CLK		7372800
+
+#define	GETREG(bas, reg)	\
+    bus_space_read_4((bas)->bst, (bas)->bsh, (reg))
+#define	SETREG(bas, reg, value)	\
+    bus_space_write_4((bas)->bst, (bas)->bsh, (reg), (value))
+
+static int msm_uart_param(struct uart_bas *, int, int, int, int);
+
+/*
+ * Low-level UART interface.
+ */
+static int	msm_probe(struct uart_bas *bas);
+static void	msm_init(struct uart_bas *bas, int, int, int, int);
+static void	msm_term(struct uart_bas *bas);
+static void	msm_putc(struct uart_bas *bas, int);
+static int	msm_rxready(struct uart_bas *bas);
+static int	msm_getc(struct uart_bas *bas, struct mtx *mtx);
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+msm_uart_param(struct uart_bas *bas, int baudrate, int databits,
+    int stopbits, int parity)
+{
+	int ulcon;
+
+	ulcon = 0;
+
+	switch (databits) {
+	case 5:
+		ulcon |= (UART_DM_5_BPS << 4);
+		break;
+	case 6:
+		ulcon |= (UART_DM_6_BPS << 4);
+		break;
+	case 7:
+		ulcon |= (UART_DM_7_BPS << 4);
+		break;
+	case 8:
+		ulcon |= (UART_DM_8_BPS << 4);
+		break;
+	default:
+		return (EINVAL);
+	}
+
+	switch (parity) {
+	case UART_PARITY_NONE:
+		ulcon |= UART_DM_NO_PARITY;
+		break;
+	case UART_PARITY_ODD:
+		ulcon |= UART_DM_ODD_PARITY;
+		break;
+	case UART_PARITY_EVEN:
+		ulcon |= UART_DM_EVEN_PARITY;
+		break;
+	case UART_PARITY_SPACE:
+		ulcon |= UART_DM_SPACE_PARITY;
+		break;
+	case UART_PARITY_MARK:
+	default:
+		return (EINVAL);
+	}
+
+	switch (stopbits) {
+	case 1:
+		ulcon |= (UART_DM_SBL_1 << 2);
+		break;
+	case 2:
+		ulcon |= (UART_DM_SBL_2 << 2);
+		break;
+	default:
+		return (EINVAL);
+	}
+	uart_setreg(bas, UART_DM_MR2, ulcon);
+
+	/* Set 115200 for both TX and RX. */;
+	uart_setreg(bas, UART_DM_CSR, UART_DM_CSR_115200);
+	uart_barrier(bas);
+
+	return (0);
+}
+
+struct uart_ops uart_msm_ops = {
+	.probe = msm_probe,
+	.init = msm_init,
+	.term = msm_term,
+	.putc = msm_putc,
+	.rxready = msm_rxready,
+	.getc = msm_getc,
+};
+
+static int
+msm_probe(struct uart_bas *bas)
+{
+
+	return (0);
+}
+
+static void
+msm_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+    int parity)
+{
+
+	if (bas->rclk == 0)
+		bas->rclk = DEF_CLK;
+
+	KASSERT(bas->rclk != 0, ("msm_init: Invalid rclk"));
+
+	/* Set default parameters */
+	msm_uart_param(bas, baudrate, databits, stopbits, parity);
+
+	/*
+	 * Configure UART mode registers MR1 and MR2.
+	 * Hardware flow control isn't supported.
+	 */
+	uart_setreg(bas, UART_DM_MR1, 0x0);
+
+	/* Reset interrupt mask register. */
+	uart_setreg(bas, UART_DM_IMR, 0);
+
+	/*
+	 * Configure Tx and Rx watermarks configuration registers.
+	 * TX watermark value is set to 0 - interrupt is generated when
+	 * FIFO level is less than or equal to 0.
+	 */
+	uart_setreg(bas, UART_DM_TFWR, UART_DM_TFW_VALUE);
+
+	/* Set RX watermark value */
+	uart_setreg(bas, UART_DM_RFWR, UART_DM_RFW_VALUE);
+
+	/*
+	 * Configure Interrupt Programming Register.
+	 * Set initial Stale timeout value.
+	 */
+	uart_setreg(bas, UART_DM_IPR, UART_DM_STALE_TIMEOUT_LSB);
+
+	/* Disable IRDA mode */
+	uart_setreg(bas, UART_DM_IRDA, 0x0);
+
+	/*
+	 * Configure and enable sim interface if required.
+	 * Configure hunt character value in HCR register.
+	 * Keep it in reset state.
+	 */
+	uart_setreg(bas, UART_DM_HCR, 0x0);
+
+	/* Issue soft reset command */
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_TX);
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_RX);
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_ERROR_STATUS);
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_BREAK_INT);
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
+
+	/* Enable/Disable Rx/Tx DM interfaces */
+	/* Disable Data Mover for now. */
+	uart_setreg(bas, UART_DM_DMEN, 0x0);
+
+	/* Enable transmitter and receiver */
+	uart_setreg(bas, UART_DM_CR, UART_DM_CR_RX_ENABLE);
+	uart_setreg(bas, UART_DM_CR, UART_DM_CR_TX_ENABLE);
+
+	uart_barrier(bas);
+}
+
+static void
+msm_term(struct uart_bas *bas)
+{
+
+	/* XXX */
+}
+
+static void
+msm_putc(struct uart_bas *bas, int c)
+{
+	int limit;
+
+	/*
+	 * Write to NO_CHARS_FOR_TX register the number of characters
+	 * to be transmitted. However, before writing TX_FIFO must
+	 * be empty as indicated by TX_READY interrupt in IMR register
+	 */
+
+	/*
+	 * Check if transmit FIFO is empty.
+	 * If not wait for TX_READY interrupt.
+	 */
+	limit = 1000;
+	if (!(uart_getreg(bas, UART_DM_SR) & UART_DM_SR_TXEMT)) {
+		while ((uart_getreg(bas, UART_DM_ISR) & UART_DM_TX_READY) == 0
+		    && --limit)
+			DELAY(4);
+	}
+	/* FIFO is ready, write number of characters to be written */
+	uart_setreg(bas, UART_DM_NO_CHARS_FOR_TX, 1);
+
+	/* Wait till TX FIFO has space */
+	while ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_TXRDY) == 0)
+		DELAY(4);
+
+	/* TX FIFO has space. Write char */
+	SETREG(bas, UART_DM_TF(0), (c & 0xff));
+}
+
+static int
+msm_rxready(struct uart_bas *bas)
+{
+
+	/* Wait for a character to come ready */
+	return ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) ==
+	    UART_DM_SR_RXRDY);
+}
+
+static int
+msm_getc(struct uart_bas *bas, struct mtx *mtx)
+{
+	int c;
+
+	uart_lock(mtx);
+
+	/* Wait for a character to come ready */
+	while ((uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) !=
+	    UART_DM_SR_RXRDY)
+		DELAY(4);
+
+	/* Check for Overrun error. If so reset Error Status */
+	if (uart_getreg(bas, UART_DM_SR) & UART_DM_SR_UART_OVERRUN)
+		uart_setreg(bas, UART_DM_CR, UART_DM_RESET_ERROR_STATUS);
+
+	/* Read char */
+	c = uart_getreg(bas, UART_DM_RF(0));
+
+	uart_unlock(mtx);
+
+	return (c);
+}
+
+/*
+ * High-level UART interface.
+ */
+struct msm_uart_softc {
+	struct uart_softc base;
+	uint32_t ier;
+};
+
+static int	msm_bus_probe(struct uart_softc *sc);
+static int	msm_bus_attach(struct uart_softc *sc);
+static int	msm_bus_flush(struct uart_softc *, int);
+static int	msm_bus_getsig(struct uart_softc *);
+static int	msm_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int	msm_bus_ipend(struct uart_softc *);
+static int	msm_bus_param(struct uart_softc *, int, int, int, int);
+static int	msm_bus_receive(struct uart_softc *);
+static int	msm_bus_setsig(struct uart_softc *, int);
+static int	msm_bus_transmit(struct uart_softc *);
+static void	msm_bus_grab(struct uart_softc *);
+static void	msm_bus_ungrab(struct uart_softc *);
+
+static kobj_method_t msm_methods[] = {
+	KOBJMETHOD(uart_probe,		msm_bus_probe),
+	KOBJMETHOD(uart_attach, 	msm_bus_attach),
+	KOBJMETHOD(uart_flush,		msm_bus_flush),
+	KOBJMETHOD(uart_getsig,		msm_bus_getsig),
+	KOBJMETHOD(uart_ioctl,		msm_bus_ioctl),
+	KOBJMETHOD(uart_ipend,		msm_bus_ipend),
+	KOBJMETHOD(uart_param,		msm_bus_param),
+	KOBJMETHOD(uart_receive,	msm_bus_receive),
+	KOBJMETHOD(uart_setsig,		msm_bus_setsig),
+	KOBJMETHOD(uart_transmit,	msm_bus_transmit),
+	KOBJMETHOD(uart_grab,		msm_bus_grab),
+	KOBJMETHOD(uart_ungrab,		msm_bus_ungrab),
+	{0, 0 }
+};
+
+int
+msm_bus_probe(struct uart_softc *sc)
+{
+
+	sc->sc_txfifosz = 64;
+	sc->sc_rxfifosz = 64;
+
+	device_set_desc(sc->sc_dev, "Qualcomm HSUART");
+
+	return (0);
+}
+
+static int
+msm_bus_attach(struct uart_softc *sc)
+{
+	struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
+	struct uart_bas *bas = &sc->sc_bas;
+
+	sc->sc_hwiflow = 0;
+	sc->sc_hwoflow = 0;
+
+	/* Set TX_READY, TXLEV, RXLEV, RXSTALE */
+	u->ier = UART_DM_IMR_ENABLED;
+
+	/* Configure Interrupt Mask register IMR */
+	uart_setreg(bas, UART_DM_IMR, u->ier);
+
+	return (0);
+}
+
+/*
+ * Write the current transmit buffer to the TX FIFO. 
+ */
+static int
+msm_bus_transmit(struct uart_softc *sc)
+{
+	struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
+	struct uart_bas *bas = &sc->sc_bas;
+	int i;
+
+	uart_lock(sc->sc_hwmtx);
+
+	/* Write some data */
+	for (i = 0; i < sc->sc_txdatasz; i++) {
+		/* Write TX data */
+		msm_putc(bas, sc->sc_txbuf[i]);
+		uart_barrier(bas);
+	}
+
+	/* TX FIFO is empty now, enable TX_READY interrupt */
+	u->ier |= UART_DM_TX_READY;
+	SETREG(bas, UART_DM_IMR, u->ier);
+	uart_barrier(bas);
+
+	/*
+	 * Inform upper layer that it is transmitting data to hardware,
+	 * this will be cleared when TXIDLE interrupt occurs.
+	 */
+	sc->sc_txbusy = 1;
+	uart_unlock(sc->sc_hwmtx);
+
+	return (0);
+}
+
+static int
+msm_bus_setsig(struct uart_softc *sc, int sig)
+{
+
+	return (0);
+}
+
+static int
+msm_bus_receive(struct uart_softc *sc)
+{
+	struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
+	struct uart_bas *bas;
+	int c;
+
+	bas = &sc->sc_bas;
+	uart_lock(sc->sc_hwmtx);
+
+	/* Initialize Receive Path and interrupt */
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
+	SETREG(bas, UART_DM_CR, UART_DM_STALE_EVENT_ENABLE);
+	u->ier |= UART_DM_RXLEV;
+	SETREG(bas, UART_DM_IMR, u->ier);
+
+	/* Loop over until we are full, or no data is available */
+	while (uart_getreg(bas, UART_DM_SR) & UART_DM_SR_RXRDY) {
+		if (uart_rx_full(sc)) {
+			/* No space left in input buffer */
+			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+			break;
+		}
+
+		/* Read RX FIFO */
+		c = uart_getreg(bas, UART_DM_RF(0));
+		uart_barrier(bas);
+
+		uart_rx_put(sc, c);
+	}
+
+	uart_unlock(sc->sc_hwmtx);
+
+	return (0);
+}
+
+static int
+msm_bus_param(struct uart_softc *sc, int baudrate, int databits,
+    int stopbits, int parity)
+{
+	int error;
+
+	if (sc->sc_bas.rclk == 0)
+		sc->sc_bas.rclk = DEF_CLK;
+
+	KASSERT(sc->sc_bas.rclk != 0, ("msm_init: Invalid rclk"));
+
+	uart_lock(sc->sc_hwmtx);
+	error = msm_uart_param(&sc->sc_bas, baudrate, databits, stopbits,
+	    parity);
+	uart_unlock(sc->sc_hwmtx);
+
+	return (error);
+}
+
+static int
+msm_bus_ipend(struct uart_softc *sc)
+{
+	struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
+	struct uart_bas *bas = &sc->sc_bas;
+	uint32_t isr;
+	int ipend;
+
+	uart_lock(sc->sc_hwmtx);
+
+	/* Get ISR status */
+	isr = GETREG(bas, UART_DM_MISR);
+
+	ipend = 0;
+
+	/* Uart RX starting, notify upper layer */
+	if (isr & UART_DM_RXLEV) {
+		u->ier &= ~UART_DM_RXLEV;
+		SETREG(bas, UART_DM_IMR, u->ier);
+		uart_barrier(bas);
+		ipend |= SER_INT_RXREADY;
+	}
+
+	/* Stale RX interrupt */
+	if (isr & UART_DM_RXSTALE) {
+		/* Disable and reset it */
+		SETREG(bas, UART_DM_CR, UART_DM_STALE_EVENT_DISABLE);
+		SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
+		uart_barrier(bas);
+		ipend |= SER_INT_RXREADY;
+	}
+
+	/* TX READY interrupt */
+	if (isr & UART_DM_TX_READY) {
+		/* Clear  TX Ready */
+		SETREG(bas, UART_DM_CR, UART_DM_CLEAR_TX_READY);
+
+		/* Disable TX_READY */
+		u->ier &= ~UART_DM_TX_READY;
+		SETREG(bas, UART_DM_IMR, u->ier);
+		uart_barrier(bas);
+
+		if (sc->sc_txbusy != 0)
+			ipend |= SER_INT_TXIDLE;
+	}
+
+	if (isr & UART_DM_TXLEV) {
+		/* TX FIFO is empty */
+		u->ier &= ~UART_DM_TXLEV;
+		SETREG(bas, UART_DM_IMR, u->ier);
+		uart_barrier(bas);
+
+		if (sc->sc_txbusy != 0)
+			ipend |= SER_INT_TXIDLE;
+	}
+
+	uart_unlock(sc->sc_hwmtx);
+	return (ipend);
+}
+
+static int
+msm_bus_flush(struct uart_softc *sc, int what)
+{
+
+	return (0);
+}
+
+static int
+msm_bus_getsig(struct uart_softc *sc)
+{
+
+	return (0);
+}
+
+static int
+msm_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+
+	return (EINVAL);
+}
+
+static void
+msm_bus_grab(struct uart_softc *sc)
+{
+	struct uart_bas *bas = &sc->sc_bas;
+
+	/*
+	 * XXX: Turn off all interrupts to enter polling mode. Leave the
+	 * saved mask alone. We'll restore whatever it was in ungrab.
+	 */
+	uart_lock(sc->sc_hwmtx);
+	SETREG(bas, UART_DM_CR, UART_DM_RESET_STALE_INT);
+	SETREG(bas, UART_DM_IMR, 0);
+	uart_barrier(bas);
+	uart_unlock(sc->sc_hwmtx);
+}
+
+static void
+msm_bus_ungrab(struct uart_softc *sc)
+{
+	struct msm_uart_softc *u = (struct msm_uart_softc *)sc;
+	struct uart_bas *bas = &sc->sc_bas;
+
+	/*
+	 * Restore previous interrupt mask
+	 */
+	uart_lock(sc->sc_hwmtx);
+	SETREG(bas, UART_DM_IMR, u->ier);
+	uart_barrier(bas);
+	uart_unlock(sc->sc_hwmtx);
+}
+
+struct uart_class uart_msm_class = {
+	"msm",
+	msm_methods,
+	sizeof(struct msm_uart_softc),
+	.uc_ops = &uart_msm_ops,
+	.uc_range = 8,
+	.uc_rclk = DEF_CLK,
+};

Copied: stable/10/sys/dev/uart/uart_dev_msm.h (from r272399, head/sys/dev/uart/uart_dev_msm.h)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/10/sys/dev/uart/uart_dev_msm.h	Sat May 23 19:27:04 2015	(r283321, copy of r272399, head/sys/dev/uart/uart_dev_msm.h)
@@ -0,0 +1,229 @@
+/*-
+ * Copyright (c) 2014 Ganbold Tsagaankhuu <ganbold@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_UART_DM_H_
+#define	_UART_DM_H_
+
+#define	UART_DM_EXTR_BITS(value, start_pos, end_pos) \
+	    ((value << (32 - end_pos)) >> (32 - (end_pos - start_pos)))
+
+/* UART Parity Mode */
+enum UART_DM_PARITY_MODE {
+	UART_DM_NO_PARITY,
+	UART_DM_ODD_PARITY,
+	UART_DM_EVEN_PARITY,
+	UART_DM_SPACE_PARITY
+};
+
+/* UART Stop Bit Length */
+enum UART_DM_STOP_BIT_LEN {
+	UART_DM_SBL_9_16,
+	UART_DM_SBL_1,
+	UART_DM_SBL_1_9_16,
+	UART_DM_SBL_2
+};
+
+/* UART Bits per Char */
+enum UART_DM_BITS_PER_CHAR {
+	UART_DM_5_BPS,
+	UART_DM_6_BPS,
+	UART_DM_7_BPS,
+	UART_DM_8_BPS
+};
+
+/* 8-N-1 Configuration */
+#define	UART_DM_8_N_1_MODE			(UART_DM_NO_PARITY | \
+						(UART_DM_SBL_1 << 2) | \
+						(UART_DM_8_BPS << 4))
+
+/* UART_DM Registers */
+
+/* UART Operational Mode Registers (HSUART) */
+#define	UART_DM_MR1				0x00
+#define	 UART_DM_MR1_AUTO_RFR_LEVEL1_BMSK	0xffffff00
+#define	 UART_DM_MR1_AUTO_RFR_LEVEL0_BMSK	0x3f
+#define	 UART_DM_MR1_CTS_CTL_BMSK		0x40
+#define	 UART_DM_MR1_RX_RDY_CTL_BMSK		0x80
+
+#define	UART_DM_MR2				0x04
+#define	 UART_DM_MR2_ERROR_MODE_BMSK		0x40
+#define	 UART_DM_MR2_BITS_PER_CHAR_BMSK		0x30
+#define	 UART_DM_MR2_STOP_BIT_LEN_BMSK		0x0c
+#define	 UART_DM_MR2_PARITY_MODE_BMSK		0x03
+#define	 UART_DM_RXBRK_ZERO_CHAR_OFF		(1 << 8)
+#define	 UART_DM_LOOPBACK			(1 << 7)
+
+/* UART Clock Selection Register, write only */
+#define	UART_DM_CSR				0x08
+#define	 UART_DM_CSR_115200			0xff
+#define	 UART_DM_CSR_57600			0xee
+#define	 UART_DM_CSR_38400			0xdd
+#define	 UART_DM_CSR_28800			0xcc
+#define	 UART_DM_CSR_19200			0xbb
+#define	 UART_DM_CSR_14400			0xaa
+#define	 UART_DM_CSR_9600			0x99
+#define	 UART_DM_CSR_7200			0x88
+#define	 UART_DM_CSR_4800			0x77
+#define	 UART_DM_CSR_3600			0x66
+#define	 UART_DM_CSR_2400			0x55
+#define	 UART_DM_CSR_1200			0x44
+#define	 UART_DM_CSR_600			0x33
+#define	 UART_DM_CSR_300			0x22
+#define	 UART_DM_CSR_150			0x11
+#define	 UART_DM_CSR_75				0x00
+
+/* UART DM TX FIFO Registers - 4, write only */
+#define	UART_DM_TF(x)				(0x70 + (4 * (x)))
+
+/* UART Command Register, write only */
+#define	UART_DM_CR				0x10
+#define	 UART_DM_CR_RX_ENABLE			(1 << 0)
+#define	 UART_DM_CR_RX_DISABLE			(1 << 1)
+#define	 UART_DM_CR_TX_ENABLE			(1 << 2)
+#define	 UART_DM_CR_TX_DISABLE			(1 << 3)
+
+/* UART_DM_CR channel command bit value (register field is bits 8:4) */
+#define	UART_DM_RESET_RX			0x10
+#define	UART_DM_RESET_TX			0x20
+#define	UART_DM_RESET_ERROR_STATUS		0x30
+#define	UART_DM_RESET_BREAK_INT			0x40
+#define	UART_DM_START_BREAK			0x50
+#define	UART_DM_STOP_BREAK			0x60
+#define	UART_DM_RESET_CTS			0x70
+#define	UART_DM_RESET_STALE_INT			0x80
+#define	UART_DM_RFR_LOW				0xD0
+#define	UART_DM_RFR_HIGH			0xE0
+#define	UART_DM_CR_PROTECTION_EN		0x100
+#define	UART_DM_STALE_EVENT_ENABLE		0x500
+#define	UART_DM_STALE_EVENT_DISABLE		0x600
+#define	UART_DM_FORCE_STALE_EVENT		0x400
+#define	UART_DM_CLEAR_TX_READY			0x300
+#define	UART_DM_RESET_TX_ERROR			0x800
+#define	UART_DM_RESET_TX_DONE			0x810
+
+/* UART Interrupt Mask Register */
+#define	UART_DM_IMR				0x14
+/* these can be used for both ISR and IMR registers */
+#define	UART_DM_TXLEV				(1 << 0)
+#define	UART_DM_RXHUNT				(1 << 1)
+#define	UART_DM_RXBRK_CHNG			(1 << 2)
+#define	UART_DM_RXSTALE				(1 << 3)
+#define	UART_DM_RXLEV				(1 << 4)
+#define	UART_DM_DELTA_CTS			(1 << 5)
+#define	UART_DM_CURRENT_CTS			(1 << 6)
+#define	UART_DM_TX_READY			(1 << 7)
+#define	UART_DM_TX_ERROR			(1 << 8)
+#define	UART_DM_TX_DONE				(1 << 9)
+#define	UART_DM_RXBREAK_START			(1 << 10)
+#define	UART_DM_RXBREAK_END			(1 << 11)
+#define	UART_DM_PAR_FRAME_ERR_IRQ		(1 << 12)
+
+#define	UART_DM_IMR_ENABLED			(UART_DM_TX_READY | \
+						UART_DM_TXLEV | \
+						UART_DM_RXLEV | \
+						UART_DM_RXSTALE)
+
+/* UART Interrupt Programming Register */
+#define	UART_DM_IPR				0x18
+#define	UART_DM_STALE_TIMEOUT_LSB		0x0f
+#define	UART_DM_STALE_TIMEOUT_MSB		0x00
+#define	UART_DM_IPR_STALE_TIMEOUT_MSB_BMSK	0xffffff80
+#define	UART_DM_IPR_STALE_LSB_BMSK		0x1f
+
+/* UART Transmit/Receive FIFO Watermark Register */
+#define	UART_DM_TFWR				0x1c
+/* Interrupt is generated when FIFO level is less than or equal to this value */
+#define	UART_DM_TFW_VALUE			0
+
+#define	UART_DM_RFWR				0x20
+/* Interrupt generated when no of words in RX FIFO is greater than this value */
+#define	UART_DM_RFW_VALUE			0
+
+/* UART Hunt Character Register */
+#define	UART_DM_HCR				0x24
+
+/* Used for RX transfer initialization */
+#define	UART_DM_DMRX				0x34
+/* Default DMRX value - any value bigger than FIFO size would be fine */
+#define	UART_DM_DMRX_DEF_VALUE			0x220
+
+/* Register to enable IRDA function */
+#define	UART_DM_IRDA				0x38
+
+/* UART Data Mover Enable Register */
+#define	UART_DM_DMEN				0x3c
+
+/* Number of characters for Transmission */
+#define	UART_DM_NO_CHARS_FOR_TX			0x40
+
+/* UART RX FIFO Base Address */
+#define	UART_DM_BADR				0x44
+
+#define	UART_DM_SIM_CFG_ADDR			0x80
+
+/* Read only registers */
+/* UART Status Register */
+#define	UART_DM_SR				0x08
+/* register field mask mapping */
+#define	 UART_DM_SR_RXRDY			(1 << 0)
+#define	 UART_DM_SR_RXFULL			(1 << 1)
+#define	 UART_DM_SR_TXRDY			(1 << 2)
+#define	 UART_DM_SR_TXEMT			(1 << 3)
+#define	 UART_DM_SR_UART_OVERRUN		(1 << 4)
+#define	 UART_DM_SR_PAR_FRAME_ERR		(1 << 5)
+#define	 UART_DM_RX_BREAK			(1 << 6)
+#define	 UART_DM_HUNT_CHAR			(1 << 7)
+#define	 UART_DM_RX_BRK_START_LAST		(1 << 8)
+
+/* UART Receive FIFO Registers - 4 in numbers */
+#define	UART_DM_RF(x)				(0x70 + (4 * (x)))
+
+/* UART Masked Interrupt Status Register */
+#define	UART_DM_MISR				0x10
+
+/* UART Interrupt Status Register */
+#define	UART_DM_ISR				0x14
+
+/* Number of characters received since the end of last RX transfer */
+#define	UART_DM_RX_TOTAL_SNAP			0x38
+
+/* UART TX FIFO Status Register */
+#define	UART_DM_TXFS				0x4c
+#define	 UART_DM_TXFS_STATE_LSB(x)		UART_DM_EXTR_BITS(x,0,6)
+#define	 UART_DM_TXFS_STATE_MSB(x)		UART_DM_EXTR_BITS(x,14,31)
+#define	 UART_DM_TXFS_BUF_STATE(x)		UART_DM_EXTR_BITS(x,7,9)
+#define	 UART_DM_TXFS_ASYNC_STATE(x)		UART_DM_EXTR_BITS(x,10,13)
+
+/* UART RX FIFO Status Register */
+#define	UART_DM_RXFS				0x50
+#define	 UART_DM_RXFS_STATE_LSB(x)		UART_DM_EXTR_BITS(x,0,6)
+#define	 UART_DM_RXFS_STATE_MSB(x)		UART_DM_EXTR_BITS(x,14,31)
+#define	 UART_DM_RXFS_BUF_STATE(x)		UART_DM_EXTR_BITS(x,7,9)
+#define	 UART_DM_RXFS_ASYNC_STATE(x)		UART_DM_EXTR_BITS(x,10,13)
+
+#endif	/* _UART_DM_H_ */

Modified: stable/10/sys/dev/uart/uart_dev_pl011.c
==============================================================================
--- stable/10/sys/dev/uart/uart_dev_pl011.c	Sat May 23 19:09:04 2015	(r283320)
+++ stable/10/sys/dev/uart/uart_dev_pl011.c	Sat May 23 19:27:04 2015	(r283321)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #define	DR_OE		(1 << 11)	/* Overrun error */
 
 #define	UART_FR		0x06		/* Flag register */
+#define	FR_TXFF		(1 << 5)	/* Transmit FIFO/reg full */
 #define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
 #define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
 
@@ -194,7 +195,8 @@ static void
 uart_pl011_putc(struct uart_bas *bas, int c)
 {
 
-	while (!(__uart_getreg(bas, UART_FR) & FR_TXFE))
+	/* Wait when TX FIFO full. Push character otherwise. */
+	while (__uart_getreg(bas, UART_FR) & FR_TXFF)
 		;
 	__uart_setreg(bas, UART_DR, c & 0xff);
 }



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