diff options
author | Renato Botelho <renato@netgate.com> | 2016-01-25 08:56:15 -0200 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2016-01-25 08:56:15 -0200 |
commit | eb84e0723f3b4bc5e40024f66fe21c14b09e9ec4 (patch) | |
tree | fec6b99d018e13f1fccbe31478aaf29a28a55642 /sys/dev/uart/uart_core.c | |
parent | c50df8e1b90c4f9b8bbffa592477c129854776ce (diff) | |
parent | 94b1bbbd44bd88b6db1c00d795cdf7675b3ae254 (diff) | |
download | FreeBSD-src-eb84e0723f3b4bc5e40024f66fe21c14b09e9ec4.zip FreeBSD-src-eb84e0723f3b4bc5e40024f66fe21c14b09e9ec4.tar.gz |
Merge remote-tracking branch 'origin/stable/10' into devel
Diffstat (limited to 'sys/dev/uart/uart_core.c')
-rw-r--r-- | sys/dev/uart/uart_core.c | 145 |
1 files changed, 94 insertions, 51 deletions
diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c index 3da37e0..b9cffe3 100644 --- a/sys/dev/uart/uart_core.c +++ b/sys/dev/uart/uart_core.c @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> #include <dev/uart/uart_cpu.h> +#include <dev/uart/uart_ppstypes.h> #include "uart_if.h" @@ -65,47 +66,47 @@ static MALLOC_DEFINE(M_UART, "UART", "UART driver"); static int uart_poll_freq = UART_POLL_FREQ; TUNABLE_INT("debug.uart_poll_freq", &uart_poll_freq); -#define PPS_MODE_DISABLED 0 -#define PPS_MODE_CTS 1 -#define PPS_MODE_DCD 2 - -static inline int -uart_pps_signal(int pps_mode) -{ - - switch(pps_mode) { - case PPS_MODE_CTS: - return (SER_CTS); - case PPS_MODE_DCD: - return (SER_DCD); - } - return (0); -} static inline int uart_pps_mode_valid(int pps_mode) { - - switch(pps_mode) { - case PPS_MODE_DISABLED: - case PPS_MODE_CTS: - case PPS_MODE_DCD: - return (true); + int opt; + + switch(pps_mode & UART_PPS_SIGNAL_MASK) { + case UART_PPS_DISABLED: + case UART_PPS_CTS: + case UART_PPS_DCD: + break; + default: + return (false); } - return (false); + + opt = pps_mode & UART_PPS_OPTION_MASK; + if ((opt & ~(UART_PPS_INVERT_PULSE | UART_PPS_NARROW_PULSE)) != 0) + return (false); + + return (true); } -static const char * -uart_pps_mode_name(int pps_mode) +static void +uart_pps_print_mode(struct uart_softc *sc) { - switch(pps_mode) { - case PPS_MODE_DISABLED: - return ("disabled"); - case PPS_MODE_CTS: - return ("CTS"); - case PPS_MODE_DCD: - return ("DCD"); + + device_printf(sc->sc_dev, "PPS capture mode: "); + switch(sc->sc_pps_mode) { + case UART_PPS_DISABLED: + printf("disabled"); + case UART_PPS_CTS: + printf("CTS"); + case UART_PPS_DCD: + printf("DCD"); + default: + printf("invalid"); } - return ("invalid"); + if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE) + printf("-Inverted"); + if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) + printf("-NarrowPulse"); + printf("\n"); } static int @@ -126,6 +127,55 @@ uart_pps_mode_sysctl(SYSCTL_HANDLER_ARGS) } static void +uart_pps_process(struct uart_softc *sc, int ser_sig) +{ + sbintime_t now; + int is_assert, pps_sig; + + /* Which signal is configured as PPS? Early out if none. */ + switch(sc->sc_pps_mode & UART_PPS_SIGNAL_MASK) { + case UART_PPS_CTS: + pps_sig = SER_CTS; + break; + case UART_PPS_DCD: + pps_sig = SER_DCD; + break; + default: + return; + } + + /* Early out if there is no change in the signal configured as PPS. */ + if ((ser_sig & SER_DELTA(pps_sig)) == 0) + return; + + /* + * In narrow-pulse mode we need to synthesize both capture and clear + * events from a single "delta occurred" indication from the uart + * hardware because the pulse width is too narrow to reliably detect + * both edges. However, when the pulse width is close to our interrupt + * processing latency we might intermittantly catch both edges. To + * guard against generating spurious events when that happens, we use a + * separate timer to ensure at least half a second elapses before we + * generate another event. + */ + pps_capture(&sc->sc_pps); + if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) { + now = getsbinuptime(); + if (now > sc->sc_pps_captime + 500 * SBT_1MS) { + sc->sc_pps_captime = now; + pps_event(&sc->sc_pps, PPS_CAPTUREASSERT); + pps_event(&sc->sc_pps, PPS_CAPTURECLEAR); + } + } else { + is_assert = ser_sig & pps_sig; + if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE) + is_assert = !is_assert; + pps_event(&sc->sc_pps, is_assert ? PPS_CAPTUREASSERT : + PPS_CAPTURECLEAR); + } +} + +static void uart_pps_init(struct uart_softc *sc) { struct sysctl_ctx_list *ctx; @@ -142,23 +192,23 @@ uart_pps_init(struct uart_softc *sc) * for one specific device. */ #ifdef UART_PPS_ON_CTS - sc->sc_pps_mode = PPS_MODE_CTS; + sc->sc_pps_mode = UART_PPS_CTS; #else - sc->sc_pps_mode = PPS_MODE_DCD; + sc->sc_pps_mode = UART_PPS_DCD; #endif TUNABLE_INT_FETCH("hw.uart.pps_mode", &sc->sc_pps_mode); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "pps_mode", CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, uart_pps_mode_sysctl, "I", - "pulse capturing mode - 0/1/2 - disabled/CTS/DCD"); + "pulse mode: 0/1/2=disabled/CTS/DCD; " + "add 0x10 to invert, 0x20 for narrow pulse"); if (!uart_pps_mode_valid(sc->sc_pps_mode)) { device_printf(sc->sc_dev, - "Invalid pps_mode %d configured; disabling PPS capture\n", + "Invalid pps_mode 0x%02x configured; disabling PPS capture\n", sc->sc_pps_mode); - sc->sc_pps_mode = PPS_MODE_DISABLED; + sc->sc_pps_mode = UART_PPS_DISABLED; } else if (bootverbose) { - device_printf(sc->sc_dev, "PPS capture mode %d (%s)\n", - sc->sc_pps_mode, uart_pps_mode_name(sc->sc_pps_mode)); + uart_pps_print_mode(sc); } sc->sc_pps.ppscap = PPS_CAPTUREBOTH; @@ -302,23 +352,16 @@ static __inline int uart_intr_sigchg(void *arg) { struct uart_softc *sc = arg; - int new, old, pps_sig, sig; + int new, old, sig; sig = UART_GETSIG(sc); /* - * Time pulse counting support. Note that both CTS and DCD are - * active-low signals. The status bit is high to indicate that - * the signal on the line is low, which corresponds to a PPS - * clear event. + * Time pulse counting support, invoked whenever the PPS parameters are + * currently set to capture either edge of the signal. */ if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) { - pps_sig = uart_pps_signal(sc->sc_pps_mode); - if (sig & SER_DELTA(pps_sig)) { - pps_capture(&sc->sc_pps); - pps_event(&sc->sc_pps, (sig & pps_sig) ? - PPS_CAPTURECLEAR : PPS_CAPTUREASSERT); - } + uart_pps_process(sc, sig); } /* |