| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: com.c,v 1.335 2015/05/04 20:25:48 macallan Exp $ */ | | 1 | /* $NetBSD: com.c,v 1.336 2015/05/04 22:59:36 jmcneill Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1998, 1999, 2004, 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1998, 1999, 2004, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Charles M. Hannum. | | 8 | * by Charles M. Hannum. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -56,27 +56,27 @@ | | | @@ -56,27 +56,27 @@ |
56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 56 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 57 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
58 | * SUCH DAMAGE. | | 58 | * SUCH DAMAGE. |
59 | * | | 59 | * |
60 | * @(#)com.c 7.5 (Berkeley) 5/16/91 | | 60 | * @(#)com.c 7.5 (Berkeley) 5/16/91 |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | /* | | 63 | /* |
64 | * COM driver, uses National Semiconductor NS16450/NS16550AF UART | | 64 | * COM driver, uses National Semiconductor NS16450/NS16550AF UART |
65 | * Supports automatic hardware flow control on StarTech ST16C650A UART | | 65 | * Supports automatic hardware flow control on StarTech ST16C650A UART |
66 | */ | | 66 | */ |
67 | | | 67 | |
68 | #include <sys/cdefs.h> | | 68 | #include <sys/cdefs.h> |
69 | __KERNEL_RCSID(0, "$NetBSD: com.c,v 1.335 2015/05/04 20:25:48 macallan Exp $"); | | 69 | __KERNEL_RCSID(0, "$NetBSD: com.c,v 1.336 2015/05/04 22:59:36 jmcneill Exp $"); |
70 | | | 70 | |
71 | #include "opt_com.h" | | 71 | #include "opt_com.h" |
72 | #include "opt_ddb.h" | | 72 | #include "opt_ddb.h" |
73 | #include "opt_kgdb.h" | | 73 | #include "opt_kgdb.h" |
74 | #include "opt_lockdebug.h" | | 74 | #include "opt_lockdebug.h" |
75 | #include "opt_multiprocessor.h" | | 75 | #include "opt_multiprocessor.h" |
76 | #include "opt_ntp.h" | | 76 | #include "opt_ntp.h" |
77 | | | 77 | |
78 | /* The COM16650 option was renamed to COM_16650. */ | | 78 | /* The COM16650 option was renamed to COM_16650. */ |
79 | #ifdef COM16650 | | 79 | #ifdef COM16650 |
80 | #error Obsolete COM16650 option; use COM_16650 instead. | | 80 | #error Obsolete COM16650 option; use COM_16650 instead. |
81 | #endif | | 81 | #endif |
82 | | | 82 | |
| @@ -370,27 +370,28 @@ comprobe1(bus_space_tag_t iot, bus_space | | | @@ -370,27 +370,28 @@ comprobe1(bus_space_tag_t iot, bus_space |
370 | | | 370 | |
371 | /* | | 371 | /* |
372 | * No locking in this routine; it is only called during attach, | | 372 | * No locking in this routine; it is only called during attach, |
373 | * or with the port already locked. | | 373 | * or with the port already locked. |
374 | */ | | 374 | */ |
375 | static void | | 375 | static void |
376 | com_enable_debugport(struct com_softc *sc) | | 376 | com_enable_debugport(struct com_softc *sc) |
377 | { | | 377 | { |
378 | | | 378 | |
379 | /* Turn on line break interrupt, set carrier. */ | | 379 | /* Turn on line break interrupt, set carrier. */ |
380 | sc->sc_ier = IER_ERXRDY; | | 380 | sc->sc_ier = IER_ERXRDY; |
381 | if (sc->sc_type == COM_TYPE_PXA2x0) | | 381 | if (sc->sc_type == COM_TYPE_PXA2x0) |
382 | sc->sc_ier |= IER_EUART | IER_ERXTOUT; | | 382 | sc->sc_ier |= IER_EUART | IER_ERXTOUT; |
383 | if (sc->sc_type == COM_TYPE_INGENIC) | | 383 | if (sc->sc_type == COM_TYPE_INGENIC || |
| | | 384 | sc->sc_type == COM_TYPE_TEGRA) |
384 | sc->sc_ier |= IER_ERXTOUT; | | 385 | sc->sc_ier |= IER_ERXTOUT; |
385 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); | | 386 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); |
386 | SET(sc->sc_mcr, MCR_DTR | MCR_RTS); | | 387 | SET(sc->sc_mcr, MCR_DTR | MCR_RTS); |
387 | CSR_WRITE_1(&sc->sc_regs, COM_REG_MCR, sc->sc_mcr); | | 388 | CSR_WRITE_1(&sc->sc_regs, COM_REG_MCR, sc->sc_mcr); |
388 | } | | 389 | } |
389 | | | 390 | |
390 | void | | 391 | void |
391 | com_attach_subr(struct com_softc *sc) | | 392 | com_attach_subr(struct com_softc *sc) |
392 | { | | 393 | { |
393 | struct com_regs *regsp = &sc->sc_regs; | | 394 | struct com_regs *regsp = &sc->sc_regs; |
394 | struct tty *tp; | | 395 | struct tty *tp; |
395 | #if defined(COM_16650) || defined(COM_16750) | | 396 | #if defined(COM_16650) || defined(COM_16750) |
396 | u_int8_t lcr; | | 397 | u_int8_t lcr; |
| @@ -456,31 +457,26 @@ com_attach_subr(struct com_softc *sc) | | | @@ -456,31 +457,26 @@ com_attach_subr(struct com_softc *sc) |
456 | | | 457 | |
457 | case COM_TYPE_OMAP: | | 458 | case COM_TYPE_OMAP: |
458 | sc->sc_fifolen = 64; | | 459 | sc->sc_fifolen = 64; |
459 | fifo_msg = "OMAP UART, working fifo"; | | 460 | fifo_msg = "OMAP UART, working fifo"; |
460 | SET(sc->sc_hwflags, COM_HW_FIFO); | | 461 | SET(sc->sc_hwflags, COM_HW_FIFO); |
461 | goto fifodelay; | | 462 | goto fifodelay; |
462 | | | 463 | |
463 | case COM_TYPE_INGENIC: | | 464 | case COM_TYPE_INGENIC: |
464 | sc->sc_fifolen = 16; | | 465 | sc->sc_fifolen = 16; |
465 | fifo_msg = "Ingenic UART, working fifo"; | | 466 | fifo_msg = "Ingenic UART, working fifo"; |
466 | SET(sc->sc_hwflags, COM_HW_FIFO); | | 467 | SET(sc->sc_hwflags, COM_HW_FIFO); |
467 | SET(sc->sc_hwflags, COM_HW_NOIEN); | | 468 | SET(sc->sc_hwflags, COM_HW_NOIEN); |
468 | goto fifodelay; | | 469 | goto fifodelay; |
469 | | | | |
470 | case COM_TYPE_TEGRA: | | | |
471 | sc->sc_fifolen = 1; | | | |
472 | fifo_msg = "Tegra UART, broken fifo"; | | | |
473 | goto fifodelay; | | | |
474 | } | | 470 | } |
475 | | | 471 | |
476 | sc->sc_fifolen = 1; | | 472 | sc->sc_fifolen = 1; |
477 | /* look for a NS 16550AF UART with FIFOs */ | | 473 | /* look for a NS 16550AF UART with FIFOs */ |
478 | if (sc->sc_type == COM_TYPE_INGENIC) { | | 474 | if (sc->sc_type == COM_TYPE_INGENIC) { |
479 | CSR_WRITE_1(regsp, COM_REG_FIFO, | | 475 | CSR_WRITE_1(regsp, COM_REG_FIFO, |
480 | FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | | | 476 | FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | |
481 | FIFO_TRIGGER_14 | FIFO_UART_ON); | | 477 | FIFO_TRIGGER_14 | FIFO_UART_ON); |
482 | } else | | 478 | } else |
483 | CSR_WRITE_1(regsp, COM_REG_FIFO, | | 479 | CSR_WRITE_1(regsp, COM_REG_FIFO, |
484 | FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); | | 480 | FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_14); |
485 | delay(100); | | 481 | delay(100); |
486 | if (ISSET(CSR_READ_1(regsp, COM_REG_IIR), IIR_FIFO_MASK) | | 482 | if (ISSET(CSR_READ_1(regsp, COM_REG_IIR), IIR_FIFO_MASK) |
| @@ -808,27 +804,28 @@ com_shutdown(struct com_softc *sc) | | | @@ -808,27 +804,28 @@ com_shutdown(struct com_softc *sc) |
808 | */ | | 804 | */ |
809 | if (ISSET(tp->t_cflag, HUPCL)) { | | 805 | if (ISSET(tp->t_cflag, HUPCL)) { |
810 | com_modem(sc, 0); | | 806 | com_modem(sc, 0); |
811 | mutex_spin_exit(&sc->sc_lock); | | 807 | mutex_spin_exit(&sc->sc_lock); |
812 | /* XXX will only timeout */ | | 808 | /* XXX will only timeout */ |
813 | (void) kpause(ttclos, false, hz, NULL); | | 809 | (void) kpause(ttclos, false, hz, NULL); |
814 | mutex_spin_enter(&sc->sc_lock); | | 810 | mutex_spin_enter(&sc->sc_lock); |
815 | } | | 811 | } |
816 | | | 812 | |
817 | /* Turn off interrupts. */ | | 813 | /* Turn off interrupts. */ |
818 | if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { | | 814 | if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) { |
819 | sc->sc_ier = IER_ERXRDY; /* interrupt on break */ | | 815 | sc->sc_ier = IER_ERXRDY; /* interrupt on break */ |
820 | if ((sc->sc_type == COM_TYPE_PXA2x0) || | | 816 | if ((sc->sc_type == COM_TYPE_PXA2x0) || |
821 | (sc->sc_type == COM_TYPE_INGENIC)) | | 817 | (sc->sc_type == COM_TYPE_INGENIC) || |
| | | 818 | (sc->sc_type == COM_TYPE_TEGRA)) |
822 | sc->sc_ier |= IER_ERXTOUT; | | 819 | sc->sc_ier |= IER_ERXTOUT; |
823 | } else | | 820 | } else |
824 | sc->sc_ier = 0; | | 821 | sc->sc_ier = 0; |
825 | | | 822 | |
826 | if (sc->sc_type == COM_TYPE_PXA2x0) | | 823 | if (sc->sc_type == COM_TYPE_PXA2x0) |
827 | sc->sc_ier |= IER_EUART; | | 824 | sc->sc_ier |= IER_EUART; |
828 | | | 825 | |
829 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); | | 826 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); |
830 | | | 827 | |
831 | mutex_spin_exit(&sc->sc_lock); | | 828 | mutex_spin_exit(&sc->sc_lock); |
832 | | | 829 | |
833 | if (sc->disable) { | | 830 | if (sc->disable) { |
834 | #ifdef DIAGNOSTIC | | 831 | #ifdef DIAGNOSTIC |
| @@ -890,27 +887,28 @@ comopen(dev_t dev, int flag, int mode, s | | | @@ -890,27 +887,28 @@ comopen(dev_t dev, int flag, int mode, s |
890 | sc->enabled = 1; | | 887 | sc->enabled = 1; |
891 | com_config(sc); | | 888 | com_config(sc); |
892 | } else { | | 889 | } else { |
893 | mutex_spin_enter(&sc->sc_lock); | | 890 | mutex_spin_enter(&sc->sc_lock); |
894 | } | | 891 | } |
895 | | | 892 | |
896 | /* Turn on interrupts. */ | | 893 | /* Turn on interrupts. */ |
897 | sc->sc_ier = IER_ERXRDY | IER_ERLS; | | 894 | sc->sc_ier = IER_ERXRDY | IER_ERLS; |
898 | if (!ISSET(tp->t_cflag, CLOCAL)) | | 895 | if (!ISSET(tp->t_cflag, CLOCAL)) |
899 | sc->sc_ier |= IER_EMSC; | | 896 | sc->sc_ier |= IER_EMSC; |
900 | | | 897 | |
901 | if (sc->sc_type == COM_TYPE_PXA2x0) | | 898 | if (sc->sc_type == COM_TYPE_PXA2x0) |
902 | sc->sc_ier |= IER_EUART | IER_ERXTOUT; | | 899 | sc->sc_ier |= IER_EUART | IER_ERXTOUT; |
903 | else if (sc->sc_type == COM_TYPE_INGENIC) | | 900 | else if (sc->sc_type == COM_TYPE_INGENIC || |
| | | 901 | sc->sc_type == COM_TYPE_TEGRA) |
904 | sc->sc_ier |= IER_ERXTOUT; | | 902 | sc->sc_ier |= IER_ERXTOUT; |
905 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); | | 903 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, sc->sc_ier); |
906 | | | 904 | |
907 | /* Fetch the current modem control status, needed later. */ | | 905 | /* Fetch the current modem control status, needed later. */ |
908 | sc->sc_msr = CSR_READ_1(&sc->sc_regs, COM_REG_MSR); | | 906 | sc->sc_msr = CSR_READ_1(&sc->sc_regs, COM_REG_MSR); |
909 | | | 907 | |
910 | /* Clear PPS capture state on first open. */ | | 908 | /* Clear PPS capture state on first open. */ |
911 | mutex_spin_enter(&timecounter_lock); | | 909 | mutex_spin_enter(&timecounter_lock); |
912 | memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state)); | | 910 | memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state)); |
913 | sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; | | 911 | sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR; |
914 | pps_init(&sc->sc_pps_state); | | 912 | pps_init(&sc->sc_pps_state); |
915 | mutex_spin_exit(&timecounter_lock); | | 913 | mutex_spin_exit(&timecounter_lock); |
916 | | | 914 | |
| @@ -1899,27 +1897,28 @@ com_rxsoft(struct com_softc *sc, struct | | | @@ -1899,27 +1897,28 @@ com_rxsoft(struct com_softc *sc, struct |
1899 | sc->sc_rbget = get; | | 1897 | sc->sc_rbget = get; |
1900 | mutex_spin_enter(&sc->sc_lock); | | 1898 | mutex_spin_enter(&sc->sc_lock); |
1901 | | | 1899 | |
1902 | cc = sc->sc_rbavail += scc - cc; | | 1900 | cc = sc->sc_rbavail += scc - cc; |
1903 | /* Buffers should be ok again, release possible block. */ | | 1901 | /* Buffers should be ok again, release possible block. */ |
1904 | if (cc >= sc->sc_r_lowat) { | | 1902 | if (cc >= sc->sc_r_lowat) { |
1905 | if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { | | 1903 | if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) { |
1906 | CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); | | 1904 | CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); |
1907 | SET(sc->sc_ier, IER_ERXRDY); | | 1905 | SET(sc->sc_ier, IER_ERXRDY); |
1908 | #ifdef COM_PXA2X0 | | 1906 | #ifdef COM_PXA2X0 |
1909 | if (sc->sc_type == COM_TYPE_PXA2x0) | | 1907 | if (sc->sc_type == COM_TYPE_PXA2x0) |
1910 | SET(sc->sc_ier, IER_ERXTOUT); | | 1908 | SET(sc->sc_ier, IER_ERXTOUT); |
1911 | #endif | | 1909 | #endif |
1912 | if (sc->sc_type == COM_TYPE_INGENIC) | | 1910 | if (sc->sc_type == COM_TYPE_INGENIC || |
| | | 1911 | sc->sc_type == COM_TYPE_TEGRA) |
1913 | SET(sc->sc_ier, IER_ERXTOUT); | | 1912 | SET(sc->sc_ier, IER_ERXTOUT); |
1914 | | | 1913 | |
1915 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, | | 1914 | CSR_WRITE_1(&sc->sc_regs, COM_REG_IER, |
1916 | sc->sc_ier); | | 1915 | sc->sc_ier); |
1917 | } | | 1916 | } |
1918 | if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { | | 1917 | if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) { |
1919 | CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); | | 1918 | CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED); |
1920 | com_hwiflow(sc); | | 1919 | com_hwiflow(sc); |
1921 | } | | 1920 | } |
1922 | } | | 1921 | } |
1923 | mutex_spin_exit(&sc->sc_lock); | | 1922 | mutex_spin_exit(&sc->sc_lock); |
1924 | } | | 1923 | } |
1925 | } | | 1924 | } |
| @@ -2105,27 +2104,28 @@ again: do { | | | @@ -2105,27 +2104,28 @@ again: do { |
2105 | } | | 2104 | } |
2106 | | | 2105 | |
2107 | /* | | 2106 | /* |
2108 | * If we're out of space, disable receive interrupts | | 2107 | * If we're out of space, disable receive interrupts |
2109 | * until the queue has drained a bit. | | 2108 | * until the queue has drained a bit. |
2110 | */ | | 2109 | */ |
2111 | if (!cc) { | | 2110 | if (!cc) { |
2112 | SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); | | 2111 | SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED); |
2113 | #ifdef COM_PXA2X0 | | 2112 | #ifdef COM_PXA2X0 |
2114 | if (sc->sc_type == COM_TYPE_PXA2x0) | | 2113 | if (sc->sc_type == COM_TYPE_PXA2x0) |
2115 | CLR(sc->sc_ier, IER_ERXRDY|IER_ERXTOUT); | | 2114 | CLR(sc->sc_ier, IER_ERXRDY|IER_ERXTOUT); |
2116 | else | | 2115 | else |
2117 | #endif | | 2116 | #endif |
2118 | if (sc->sc_type == COM_TYPE_INGENIC) | | 2117 | if (sc->sc_type == COM_TYPE_INGENIC || |
| | | 2118 | sc->sc_type == COM_TYPE_TEGRA) |
2119 | CLR(sc->sc_ier, | | 2119 | CLR(sc->sc_ier, |
2120 | IER_ERXRDY | IER_ERXTOUT); | | 2120 | IER_ERXRDY | IER_ERXTOUT); |
2121 | else | | 2121 | else |
2122 | CLR(sc->sc_ier, IER_ERXRDY); | | 2122 | CLR(sc->sc_ier, IER_ERXRDY); |
2123 | CSR_WRITE_1(regsp, COM_REG_IER, sc->sc_ier); | | 2123 | CSR_WRITE_1(regsp, COM_REG_IER, sc->sc_ier); |
2124 | } | | 2124 | } |
2125 | } else { | | 2125 | } else { |
2126 | if ((iir & (IIR_RXRDY|IIR_TXRDY)) == IIR_RXRDY) { | | 2126 | if ((iir & (IIR_RXRDY|IIR_TXRDY)) == IIR_RXRDY) { |
2127 | (void) CSR_READ_1(regsp, COM_REG_RXDATA); | | 2127 | (void) CSR_READ_1(regsp, COM_REG_RXDATA); |
2128 | continue; | | 2128 | continue; |
2129 | } | | 2129 | } |
2130 | } | | 2130 | } |
2131 | | | 2131 | |