1*dbfa10e5Sriastradh /* $NetBSD: imxuart.c,v 1.30 2022/10/26 23:38:06 riastradh Exp $ */
25a80dc5fSbsh
35a80dc5fSbsh /*
45a80dc5fSbsh * Copyright (c) 2009, 2010 Genetec Corporation. All rights reserved.
55a80dc5fSbsh * Written by Hiroyuki Bessho for Genetec Corporation.
65a80dc5fSbsh *
75a80dc5fSbsh * Redistribution and use in source and binary forms, with or without
85a80dc5fSbsh * modification, are permitted provided that the following conditions
95a80dc5fSbsh * are met:
105a80dc5fSbsh * 1. Redistributions of source code must retain the above copyright
115a80dc5fSbsh * notice, this list of conditions and the following disclaimer.
125a80dc5fSbsh * 2. Redistributions in binary form must reproduce the above copyright
135a80dc5fSbsh * notice, this list of conditions and the following disclaimer in the
145a80dc5fSbsh * documentation and/or other materials provided with the distribution.
155a80dc5fSbsh *
165a80dc5fSbsh * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND
175a80dc5fSbsh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
185a80dc5fSbsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
195a80dc5fSbsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION
205a80dc5fSbsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
215a80dc5fSbsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
225a80dc5fSbsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
235a80dc5fSbsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
245a80dc5fSbsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
255a80dc5fSbsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
265a80dc5fSbsh * POSSIBILITY OF SUCH DAMAGE.
275a80dc5fSbsh *
285a80dc5fSbsh */
295a80dc5fSbsh
305a80dc5fSbsh /*
315a80dc5fSbsh * derived from sys/dev/ic/com.c
325a80dc5fSbsh */
335a80dc5fSbsh
345a80dc5fSbsh /*-
355a80dc5fSbsh * Copyright (c) 1998, 1999, 2004, 2008 The NetBSD Foundation, Inc.
365a80dc5fSbsh * All rights reserved.
375a80dc5fSbsh *
385a80dc5fSbsh * This code is derived from software contributed to The NetBSD Foundation
395a80dc5fSbsh * by Charles M. Hannum.
405a80dc5fSbsh *
415a80dc5fSbsh * Redistribution and use in source and binary forms, with or without
425a80dc5fSbsh * modification, are permitted provided that the following conditions
435a80dc5fSbsh * are met:
445a80dc5fSbsh * 1. Redistributions of source code must retain the above copyright
455a80dc5fSbsh * notice, this list of conditions and the following disclaimer.
465a80dc5fSbsh * 2. Redistributions in binary form must reproduce the above copyright
475a80dc5fSbsh * notice, this list of conditions and the following disclaimer in the
485a80dc5fSbsh * documentation and/or other materials provided with the distribution.
495a80dc5fSbsh *
505a80dc5fSbsh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
515a80dc5fSbsh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
525a80dc5fSbsh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
535a80dc5fSbsh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
545a80dc5fSbsh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
555a80dc5fSbsh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
565a80dc5fSbsh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
575a80dc5fSbsh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
585a80dc5fSbsh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
595a80dc5fSbsh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
605a80dc5fSbsh * POSSIBILITY OF SUCH DAMAGE.
615a80dc5fSbsh */
625a80dc5fSbsh
635a80dc5fSbsh /*
645a80dc5fSbsh * Copyright (c) 1991 The Regents of the University of California.
655a80dc5fSbsh * All rights reserved.
665a80dc5fSbsh *
675a80dc5fSbsh * Redistribution and use in source and binary forms, with or without
685a80dc5fSbsh * modification, are permitted provided that the following conditions
695a80dc5fSbsh * are met:
705a80dc5fSbsh * 1. Redistributions of source code must retain the above copyright
715a80dc5fSbsh * notice, this list of conditions and the following disclaimer.
725a80dc5fSbsh * 2. Redistributions in binary form must reproduce the above copyright
735a80dc5fSbsh * notice, this list of conditions and the following disclaimer in the
745a80dc5fSbsh * documentation and/or other materials provided with the distribution.
755a80dc5fSbsh * 3. Neither the name of the University nor the names of its contributors
765a80dc5fSbsh * may be used to endorse or promote products derived from this software
775a80dc5fSbsh * without specific prior written permission.
785a80dc5fSbsh *
795a80dc5fSbsh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
805a80dc5fSbsh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
815a80dc5fSbsh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
825a80dc5fSbsh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
835a80dc5fSbsh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
845a80dc5fSbsh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
855a80dc5fSbsh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
865a80dc5fSbsh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
875a80dc5fSbsh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
885a80dc5fSbsh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
895a80dc5fSbsh * SUCH DAMAGE.
905a80dc5fSbsh *
915a80dc5fSbsh * @(#)com.c 7.5 (Berkeley) 5/16/91
925a80dc5fSbsh */
935a80dc5fSbsh
945a80dc5fSbsh /*
955a80dc5fSbsh * driver for UART in i.MX SoC.
965a80dc5fSbsh */
975a80dc5fSbsh
985a80dc5fSbsh #include <sys/cdefs.h>
99*dbfa10e5Sriastradh __KERNEL_RCSID(0, "$NetBSD: imxuart.c,v 1.30 2022/10/26 23:38:06 riastradh Exp $");
1005a80dc5fSbsh
1015a80dc5fSbsh #include "opt_imxuart.h"
1025a80dc5fSbsh #include "opt_ddb.h"
103a4103ccdSryo #include "opt_ddbparam.h"
1045a80dc5fSbsh #include "opt_kgdb.h"
1055a80dc5fSbsh #include "opt_lockdebug.h"
1065a80dc5fSbsh #include "opt_multiprocessor.h"
1075a80dc5fSbsh #include "opt_ntp.h"
1085a80dc5fSbsh #include "opt_imxuart.h"
1095a80dc5fSbsh
1107b0b7dedStls #ifdef RND_COM
111445478ceSriastradh #include <sys/rndsource.h>
1125a80dc5fSbsh #endif
1135a80dc5fSbsh
1145a80dc5fSbsh #ifndef IMXUART_TOLERANCE
1155a80dc5fSbsh #define IMXUART_TOLERANCE 30 /* baud rate tolerance, in 0.1% units */
1165a80dc5fSbsh #endif
1175a80dc5fSbsh
1185a80dc5fSbsh #ifndef IMXUART_FREQDIV
1195a80dc5fSbsh #define IMXUART_FREQDIV 2 /* XXX */
1205a80dc5fSbsh #endif
1215a80dc5fSbsh
1225a80dc5fSbsh #ifndef IMXUART_FREQ
1235a80dc5fSbsh #define IMXUART_FREQ (56900000)
1245a80dc5fSbsh #endif
1255a80dc5fSbsh
1265a80dc5fSbsh /*
1275a80dc5fSbsh * Override cnmagic(9) macro before including <sys/systm.h>.
1285a80dc5fSbsh * We need to know if cn_check_magic triggered debugger, so set a flag.
1295a80dc5fSbsh * Callers of cn_check_magic must declare int cn_trapped = 0;
1305a80dc5fSbsh * XXX: this is *ugly*!
1315a80dc5fSbsh */
1325a80dc5fSbsh #define cn_trap() \
1335a80dc5fSbsh do { \
1345a80dc5fSbsh console_debugger(); \
1355a80dc5fSbsh cn_trapped = 1; \
1365a80dc5fSbsh } while (/* CONSTCOND */ 0)
1375a80dc5fSbsh
1385a80dc5fSbsh #include <sys/param.h>
139825088edSmatt #include <sys/systm.h>
1405a80dc5fSbsh #include <sys/ioctl.h>
1415a80dc5fSbsh #include <sys/select.h>
1425a80dc5fSbsh #include <sys/poll.h>
143825088edSmatt #include <sys/tty.h>
1445a80dc5fSbsh #include <sys/proc.h>
1455a80dc5fSbsh #include <sys/conf.h>
1465a80dc5fSbsh #include <sys/file.h>
1475a80dc5fSbsh #include <sys/uio.h>
1485a80dc5fSbsh #include <sys/kernel.h>
1495a80dc5fSbsh #include <sys/syslog.h>
1505a80dc5fSbsh #include <sys/device.h>
15145a935baSthorpej #include <sys/kmem.h>
1525a80dc5fSbsh #include <sys/timepps.h>
1535a80dc5fSbsh #include <sys/vnode.h>
1545a80dc5fSbsh #include <sys/kauth.h>
1555a80dc5fSbsh #include <sys/intr.h>
156825088edSmatt
1575a80dc5fSbsh #include <sys/bus.h>
1585a80dc5fSbsh
159*dbfa10e5Sriastradh #include <ddb/db_active.h>
160*dbfa10e5Sriastradh
161825088edSmatt #include <arm/imx/imxuartreg.h>
162825088edSmatt #include <arm/imx/imxuartvar.h>
1635a80dc5fSbsh #include <dev/cons.h>
1645a80dc5fSbsh
1655a80dc5fSbsh #ifndef IMXUART_RING_SIZE
1665a80dc5fSbsh #define IMXUART_RING_SIZE 2048
1675a80dc5fSbsh #endif
1685a80dc5fSbsh
1695a80dc5fSbsh int imxuspeed(long, struct imxuart_baudrate_ratio *);
1705a80dc5fSbsh int imxuparam(struct tty *, struct termios *);
1715a80dc5fSbsh void imxustart(struct tty *);
1725a80dc5fSbsh int imxuhwiflow(struct tty *, int);
1735a80dc5fSbsh
1745a80dc5fSbsh void imxuart_shutdown(struct imxuart_softc *);
1755a80dc5fSbsh void imxuart_loadchannelregs(struct imxuart_softc *);
1765a80dc5fSbsh void imxuart_hwiflow(struct imxuart_softc *);
1775a80dc5fSbsh void imxuart_break(struct imxuart_softc *, bool);
1785a80dc5fSbsh void imxuart_modem(struct imxuart_softc *, int);
1795a80dc5fSbsh void tiocm_to_imxu(struct imxuart_softc *, u_long, int);
1805a80dc5fSbsh int imxuart_to_tiocm(struct imxuart_softc *);
1815a80dc5fSbsh void imxuart_iflush(struct imxuart_softc *);
1825a80dc5fSbsh int imxuintr(void *);
1835a80dc5fSbsh
1845a80dc5fSbsh int imxuart_common_getc(dev_t, struct imxuart_regs *);
1855a80dc5fSbsh void imxuart_common_putc(dev_t, struct imxuart_regs *, int);
1865a80dc5fSbsh
1875a80dc5fSbsh
188d0174d87Sryo int imxuart_init(struct imxuart_regs *, int, tcflag_t, int);
1895a80dc5fSbsh
1905a80dc5fSbsh int imxucngetc(dev_t);
1915a80dc5fSbsh void imxucnputc(dev_t, int);
1925a80dc5fSbsh void imxucnpollc(dev_t, int);
1935a80dc5fSbsh
1945a80dc5fSbsh static void imxuintr_read(struct imxuart_softc *);
1955a80dc5fSbsh static void imxuintr_send(struct imxuart_softc *);
1965a80dc5fSbsh
1975a80dc5fSbsh static void imxuart_enable_debugport(struct imxuart_softc *);
1985a80dc5fSbsh static void imxuart_disable_all_interrupts(struct imxuart_softc *);
1995a80dc5fSbsh static void imxuart_control_rxint(struct imxuart_softc *, bool);
2005a80dc5fSbsh static void imxuart_control_txint(struct imxuart_softc *, bool);
2015a80dc5fSbsh static u_int imxuart_txfifo_space(struct imxuart_softc *sc);
2025a80dc5fSbsh
2035a80dc5fSbsh static uint32_t cflag_to_ucr2(tcflag_t, uint32_t);
2045a80dc5fSbsh
2055a80dc5fSbsh #define integrate static inline
2065a80dc5fSbsh void imxusoft(void *);
2075a80dc5fSbsh integrate void imxuart_rxsoft(struct imxuart_softc *, struct tty *);
2085a80dc5fSbsh integrate void imxuart_txsoft(struct imxuart_softc *, struct tty *);
2095a80dc5fSbsh integrate void imxuart_stsoft(struct imxuart_softc *, struct tty *);
2105a80dc5fSbsh integrate void imxuart_schedrx(struct imxuart_softc *);
2115a80dc5fSbsh void imxudiag(void *);
2125a80dc5fSbsh static void imxuart_load_speed(struct imxuart_softc *);
2135a80dc5fSbsh static void imxuart_load_params(struct imxuart_softc *);
2145a80dc5fSbsh integrate void imxuart_load_pendings(struct imxuart_softc *);
2155a80dc5fSbsh
2165a80dc5fSbsh
2175a80dc5fSbsh extern struct cfdriver imxuart_cd;
2185a80dc5fSbsh
2195a80dc5fSbsh dev_type_open(imxuopen);
2205a80dc5fSbsh dev_type_close(imxuclose);
2215a80dc5fSbsh dev_type_read(imxuread);
2225a80dc5fSbsh dev_type_write(imxuwrite);
2235a80dc5fSbsh dev_type_ioctl(imxuioctl);
2245a80dc5fSbsh dev_type_stop(imxustop);
2255a80dc5fSbsh dev_type_tty(imxutty);
2265a80dc5fSbsh dev_type_poll(imxupoll);
2275a80dc5fSbsh
2285a80dc5fSbsh const struct cdevsw imxcom_cdevsw = {
229a68f9396Sdholland .d_open = imxuopen,
230a68f9396Sdholland .d_close = imxuclose,
231a68f9396Sdholland .d_read = imxuread,
232a68f9396Sdholland .d_write = imxuwrite,
233a68f9396Sdholland .d_ioctl = imxuioctl,
234a68f9396Sdholland .d_stop = imxustop,
235a68f9396Sdholland .d_tty = imxutty,
236a68f9396Sdholland .d_poll = imxupoll,
237a68f9396Sdholland .d_mmap = nommap,
238a68f9396Sdholland .d_kqfilter = ttykqfilter,
239f9228f42Sdholland .d_discard = nodiscard,
240a68f9396Sdholland .d_flag = D_TTY
2415a80dc5fSbsh };
2425a80dc5fSbsh
2435a80dc5fSbsh /*
2445a80dc5fSbsh * Make this an option variable one can patch.
2455a80dc5fSbsh * But be warned: this must be a power of 2!
2465a80dc5fSbsh */
2475a80dc5fSbsh u_int imxuart_rbuf_size = IMXUART_RING_SIZE;
2485a80dc5fSbsh
2495a80dc5fSbsh /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
2505a80dc5fSbsh u_int imxuart_rbuf_hiwat = (IMXUART_RING_SIZE * 1) / 4;
2515a80dc5fSbsh u_int imxuart_rbuf_lowat = (IMXUART_RING_SIZE * 3) / 4;
2525a80dc5fSbsh
2535a80dc5fSbsh static struct imxuart_regs imxuconsregs;
2545a80dc5fSbsh static int imxuconsattached;
2555a80dc5fSbsh static int imxuconsrate;
2565a80dc5fSbsh static tcflag_t imxuconscflag;
2575a80dc5fSbsh static struct cnm_state imxuart_cnm_state;
2585a80dc5fSbsh
2595a80dc5fSbsh u_int imxuart_freq = IMXUART_FREQ;
2605a80dc5fSbsh u_int imxuart_freqdiv = IMXUART_FREQDIV;
2615a80dc5fSbsh
2625a80dc5fSbsh #ifdef KGDB
2635a80dc5fSbsh #include <sys/kgdb.h>
2645a80dc5fSbsh
2655a80dc5fSbsh static struct imxuart_regs imxu_kgdb_regs;
2665a80dc5fSbsh static int imxu_kgdb_attached;
2675a80dc5fSbsh
2685a80dc5fSbsh int imxuart_kgdb_getc(void *);
2695a80dc5fSbsh void imxuart_kgdb_putc(void *, int);
2705a80dc5fSbsh #endif /* KGDB */
271825088edSmatt
272a0a6c85fSchristos #define IMXUART_DIALOUT_MASK TTDIALOUT_MASK
273825088edSmatt
274a0a6c85fSchristos #define IMXUART_UNIT(x) TTUNIT(x)
275a0a6c85fSchristos #define IMXUART_DIALOUT(x) TTDIALOUT(x)
2765a80dc5fSbsh
2775a80dc5fSbsh #define IMXUART_ISALIVE(sc) ((sc)->enabled != 0 && \
2785a80dc5fSbsh device_is_active((sc)->sc_dev))
2795a80dc5fSbsh
2805a80dc5fSbsh #define BR BUS_SPACE_BARRIER_READ
2815a80dc5fSbsh #define BW BUS_SPACE_BARRIER_WRITE
2825a80dc5fSbsh #define IMXUART_BARRIER(r, f) \
2835a80dc5fSbsh bus_space_barrier((r)->ur_iot, (r)->ur_ioh, 0, IMX_UART_SIZE, (f))
284825088edSmatt
285825088edSmatt
2865a80dc5fSbsh void
imxuart_attach_common(device_t parent,device_t self,bus_space_tag_t iot,paddr_t iobase,size_t size,int intr,int flags)2878af7e1f7Sbsh imxuart_attach_common(device_t parent, device_t self,
2885a80dc5fSbsh bus_space_tag_t iot, paddr_t iobase, size_t size, int intr, int flags)
289825088edSmatt {
2904f4d98d9Shkenken struct imxuart_softc *sc = device_private(self);
2915a80dc5fSbsh struct imxuart_regs *regsp = &sc->sc_regs;
2925a80dc5fSbsh bus_space_handle_t ioh;
293825088edSmatt
2945a80dc5fSbsh aprint_naive("\n");
2955a80dc5fSbsh aprint_normal("\n");
296825088edSmatt
2975a80dc5fSbsh sc->sc_dev = self;
2985a80dc5fSbsh
2995a80dc5fSbsh if (size <= 0)
3005a80dc5fSbsh size = IMX_UART_SIZE;
3015a80dc5fSbsh
3025a80dc5fSbsh sc->sc_intr = intr;
3035a80dc5fSbsh regsp->ur_iot = iot;
3045a80dc5fSbsh regsp->ur_iobase = iobase;
3055a80dc5fSbsh
3065a80dc5fSbsh if (bus_space_map(iot, regsp->ur_iobase, size, 0, &ioh)) {
3075a80dc5fSbsh return;
3085a80dc5fSbsh }
3095a80dc5fSbsh regsp->ur_ioh = ioh;
3105a80dc5fSbsh
3118b06bd99Shkenken sc->sc_ih = intr_establish(sc->sc_intr, IPL_SERIAL, IST_LEVEL,
3128b06bd99Shkenken imxuintr, sc);
3138b06bd99Shkenken if (sc->sc_ih == NULL) {
3148b06bd99Shkenken aprint_error_dev(sc->sc_dev, "intr_establish failed\n");
3158b06bd99Shkenken return;
3168b06bd99Shkenken }
3178b06bd99Shkenken
3184f4d98d9Shkenken imxuart_attach_subr(sc);
3194f4d98d9Shkenken }
3204f4d98d9Shkenken
3214f4d98d9Shkenken void
imxuart_attach_subr(struct imxuart_softc * sc)3224f4d98d9Shkenken imxuart_attach_subr(struct imxuart_softc *sc)
3234f4d98d9Shkenken {
3244f4d98d9Shkenken struct imxuart_regs *regsp = &sc->sc_regs;
3254f4d98d9Shkenken bus_space_tag_t iot = regsp->ur_iot;
3264f4d98d9Shkenken bus_space_handle_t ioh = regsp->ur_ioh;
3274f4d98d9Shkenken struct tty *tp;
3284f4d98d9Shkenken
3295a80dc5fSbsh callout_init(&sc->sc_diag_callout, 0);
3305a80dc5fSbsh mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_HIGH);
3315a80dc5fSbsh
332d0174d87Sryo if (regsp->ur_iobase != imxuconsregs.ur_iobase)
333d0174d87Sryo imxuart_init(&sc->sc_regs, TTYDEF_SPEED, TTYDEF_CFLAG, false);
334d0174d87Sryo
3355a80dc5fSbsh bus_space_read_region_4(iot, ioh, IMX_UCR1, sc->sc_ucr, 4);
3365a80dc5fSbsh sc->sc_ucr2_d = sc->sc_ucr2;
3375a80dc5fSbsh
3385a80dc5fSbsh /* Disable interrupts before configuring the device. */
3395a80dc5fSbsh imxuart_disable_all_interrupts(sc);
3405a80dc5fSbsh
3415a80dc5fSbsh if (regsp->ur_iobase == imxuconsregs.ur_iobase) {
3425a80dc5fSbsh imxuconsattached = 1;
3435a80dc5fSbsh
3445a80dc5fSbsh /* Make sure the console is always "hardwired". */
3455a80dc5fSbsh #if 0
3465a80dc5fSbsh delay(10000); /* wait for output to finish */
3475a80dc5fSbsh #endif
3485a80dc5fSbsh SET(sc->sc_hwflags, IMXUART_HW_CONSOLE);
3495a80dc5fSbsh SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
3505a80dc5fSbsh }
3515a80dc5fSbsh
3525a80dc5fSbsh
3532626d576Srmind tp = tty_alloc();
3545a80dc5fSbsh tp->t_oproc = imxustart;
3555a80dc5fSbsh tp->t_param = imxuparam;
3565a80dc5fSbsh tp->t_hwiflow = imxuhwiflow;
3575a80dc5fSbsh
3585a80dc5fSbsh sc->sc_tty = tp;
35945a935baSthorpej sc->sc_rbuf = kmem_alloc(sizeof (*sc->sc_rbuf) * imxuart_rbuf_size,
36045a935baSthorpej KM_SLEEP);
3615a80dc5fSbsh sc->sc_rbuf_size = imxuart_rbuf_size;
3625a80dc5fSbsh sc->sc_rbuf_in = sc->sc_rbuf_out = 0;
3635a80dc5fSbsh sc->sc_txfifo_len = 32;
3645a80dc5fSbsh sc->sc_txfifo_thresh = 16; /* when USR1.TRDY, fifo has space
3655a80dc5fSbsh * for this many characters */
3665a80dc5fSbsh
367825088edSmatt tty_attach(tp);
368825088edSmatt
3695a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_CONSOLE)) {
3705a80dc5fSbsh int maj;
371825088edSmatt
3725a80dc5fSbsh /* locate the major number */
3735a80dc5fSbsh maj = cdevsw_lookup_major(&imxcom_cdevsw);
3745a80dc5fSbsh
3755a80dc5fSbsh if (maj != NODEVMAJOR) {
3765a80dc5fSbsh tp->t_dev = cn_tab->cn_dev = makedev(maj,
3775a80dc5fSbsh device_unit(sc->sc_dev));
3785a80dc5fSbsh
3795a80dc5fSbsh aprint_normal_dev(sc->sc_dev, "console\n");
3805a80dc5fSbsh }
381825088edSmatt }
382825088edSmatt
3835a80dc5fSbsh #ifdef KGDB
3845a80dc5fSbsh /*
3855a80dc5fSbsh * Allow kgdb to "take over" this port. If this is
3865a80dc5fSbsh * not the console and is the kgdb device, it has
3875a80dc5fSbsh * exclusive use. If it's the console _and_ the
3885a80dc5fSbsh * kgdb device, it doesn't.
3895a80dc5fSbsh */
3905a80dc5fSbsh if (regsp->ur_iobase == imxu_kgdb_regs.ur_iobase) {
3915a80dc5fSbsh if (!ISSET(sc->sc_hwflags, IMXUART_HW_CONSOLE)) {
3925a80dc5fSbsh imxu_kgdb_attached = 1;
3935a80dc5fSbsh
3945a80dc5fSbsh SET(sc->sc_hwflags, IMXUART_HW_KGDB);
3955a80dc5fSbsh }
3965a80dc5fSbsh aprint_normal_dev(sc->sc_dev, "kgdb\n");
3975a80dc5fSbsh }
3985a80dc5fSbsh #endif
3995a80dc5fSbsh
4005a80dc5fSbsh sc->sc_si = softint_establish(SOFTINT_SERIAL, imxusoft, sc);
4015a80dc5fSbsh
4027b0b7dedStls #ifdef RND_COM
4035a80dc5fSbsh rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
404ea6af427Stls RND_TYPE_TTY, RND_FLAG_COLLECT_TIME |
405ea6af427Stls RND_FLAG_ESTIMATE_TIME);
4065a80dc5fSbsh #endif
4075a80dc5fSbsh
4085a80dc5fSbsh /* if there are no enable/disable functions, assume the device
4095a80dc5fSbsh is always enabled */
4105a80dc5fSbsh if (!sc->enable)
4115a80dc5fSbsh sc->enabled = 1;
4125a80dc5fSbsh
4135a80dc5fSbsh imxuart_enable_debugport(sc);
4145a80dc5fSbsh
4155a80dc5fSbsh SET(sc->sc_hwflags, IMXUART_HW_DEV_OK);
4165a80dc5fSbsh
4175a80dc5fSbsh //shutdownhook_establish(imxuart_shutdownhook, sc);
4185a80dc5fSbsh
4195a80dc5fSbsh
4205a80dc5fSbsh #if 0
4215a80dc5fSbsh {
4225a80dc5fSbsh uint32_t reg;
4235a80dc5fSbsh reg = bus_space_read_4(iot, ioh, IMX_UCR1);
4245a80dc5fSbsh reg |= IMX_UCR1_TXDMAEN | IMX_UCR1_RXDMAEN;
4255a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR1, reg);
4265a80dc5fSbsh }
4275a80dc5fSbsh #endif
4285a80dc5fSbsh }
4295a80dc5fSbsh
4305a80dc5fSbsh /*
4315a80dc5fSbsh * baudrate = RefFreq / (16 * (UMBR + 1)/(UBIR + 1))
4325a80dc5fSbsh *
4335a80dc5fSbsh * (UBIR + 1) / (UBMR + 1) = (16 * BaurdRate) / RefFreq
4345a80dc5fSbsh */
4355a80dc5fSbsh
4365a80dc5fSbsh static long
gcd(long m,long n)4375a80dc5fSbsh gcd(long m, long n)
4385a80dc5fSbsh {
4395a80dc5fSbsh
4405a80dc5fSbsh if (m < n)
4415a80dc5fSbsh return gcd(n, m);
4425a80dc5fSbsh
4435a80dc5fSbsh if (n <= 0)
4445a80dc5fSbsh return m;
4455a80dc5fSbsh return gcd(n, m % n);
4465a80dc5fSbsh }
4475a80dc5fSbsh
4485a80dc5fSbsh int
imxuspeed(long speed,struct imxuart_baudrate_ratio * ratio)4495a80dc5fSbsh imxuspeed(long speed, struct imxuart_baudrate_ratio *ratio)
4505a80dc5fSbsh {
4515a80dc5fSbsh #define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
4525a80dc5fSbsh long b = 16 * speed;
4535a80dc5fSbsh long f = imxuart_freq / imxuart_freqdiv;
4545a80dc5fSbsh long d;
4555a80dc5fSbsh int err = 0;
4565a80dc5fSbsh
4575a80dc5fSbsh /* reduce b/f */
4585a80dc5fSbsh while ((f > (1<<16) || b > (1<<16)) && (d = gcd(f, b)) > 1) {
4595a80dc5fSbsh f /= d;
4605a80dc5fSbsh b /= d;
4615a80dc5fSbsh }
4625a80dc5fSbsh
4635a80dc5fSbsh
4645a80dc5fSbsh while (f > (1<<16) || b > (1<<16)) {
4655a80dc5fSbsh f /= 2;
4665a80dc5fSbsh b /= 2;
4675a80dc5fSbsh }
4685a80dc5fSbsh if (f <= 0 || b <= 0)
4695a80dc5fSbsh return -1;
4705a80dc5fSbsh
4715a80dc5fSbsh #ifdef DIAGNOSTIC
4725a80dc5fSbsh err = divrnd(((uint64_t)imxuart_freq) * 1000 / imxuart_freqdiv,
4735a80dc5fSbsh (uint64_t)speed * 16 * f / b) - 1000;
4745a80dc5fSbsh if (err < 0)
4755a80dc5fSbsh err = -err;
4765a80dc5fSbsh #endif
4775a80dc5fSbsh
4785a80dc5fSbsh ratio->numerator = b-1;
4795a80dc5fSbsh ratio->modulator = f-1;
4805a80dc5fSbsh
4815a80dc5fSbsh if (err > IMXUART_TOLERANCE)
4825a80dc5fSbsh return -1;
4835a80dc5fSbsh
4845a80dc5fSbsh return 0;
4855a80dc5fSbsh #undef divrnd
4865a80dc5fSbsh }
4875a80dc5fSbsh
4885a80dc5fSbsh #ifdef IMXUART_DEBUG
4895a80dc5fSbsh int imxuart_debug = 0;
4905a80dc5fSbsh
4915a80dc5fSbsh void imxustatus(struct imxuart_softc *, const char *);
492825088edSmatt void
imxustatus(struct imxuart_softc * sc,const char * str)4935a80dc5fSbsh imxustatus(struct imxuart_softc *sc, const char *str)
494825088edSmatt {
4955a80dc5fSbsh struct tty *tp = sc->sc_tty;
496825088edSmatt
4975a80dc5fSbsh aprint_normal_dev(sc->sc_dev,
4985a80dc5fSbsh "%s %cclocal %cdcd %cts_carr_on %cdtr %ctx_stopped\n",
4995a80dc5fSbsh str,
5005a80dc5fSbsh ISSET(tp->t_cflag, CLOCAL) ? '+' : '-',
5015a80dc5fSbsh ISSET(sc->sc_msr, MSR_DCD) ? '+' : '-',
5025a80dc5fSbsh ISSET(tp->t_state, TS_CARR_ON) ? '+' : '-',
5035a80dc5fSbsh ISSET(sc->sc_mcr, MCR_DTR) ? '+' : '-',
5045a80dc5fSbsh sc->sc_tx_stopped ? '+' : '-');
5055a80dc5fSbsh
5065a80dc5fSbsh aprint_normal_dev(sc->sc_dev,
5075a80dc5fSbsh "%s %ccrtscts %ccts %cts_ttstop %crts rx_flags=0x%x\n",
5085a80dc5fSbsh str,
5095a80dc5fSbsh ISSET(tp->t_cflag, CRTSCTS) ? '+' : '-',
5105a80dc5fSbsh ISSET(sc->sc_msr, MSR_CTS) ? '+' : '-',
5115a80dc5fSbsh ISSET(tp->t_state, TS_TTSTOP) ? '+' : '-',
5125a80dc5fSbsh ISSET(sc->sc_mcr, MCR_RTS) ? '+' : '-',
5135a80dc5fSbsh sc->sc_rx_flags);
514825088edSmatt }
5155a80dc5fSbsh #endif
516825088edSmatt
5175a80dc5fSbsh #if 0
5185a80dc5fSbsh int
5195a80dc5fSbsh imxuart_detach(device_t self, int flags)
520825088edSmatt {
5215a80dc5fSbsh struct imxuart_softc *sc = device_private(self);
5225a80dc5fSbsh int maj, mn;
523825088edSmatt
5245a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_CONSOLE))
5255a80dc5fSbsh return EBUSY;
5265a80dc5fSbsh
5275a80dc5fSbsh /* locate the major number */
5285a80dc5fSbsh maj = cdevsw_lookup_major(&imxcom_cdevsw);
5295a80dc5fSbsh
5305a80dc5fSbsh /* Nuke the vnodes for any open instances. */
5315a80dc5fSbsh mn = device_unit(self);
5325a80dc5fSbsh vdevgone(maj, mn, mn, VCHR);
5335a80dc5fSbsh
5345a80dc5fSbsh mn |= IMXUART_DIALOUT_MASK;
5355a80dc5fSbsh vdevgone(maj, mn, mn, VCHR);
5365a80dc5fSbsh
5375a80dc5fSbsh if (sc->sc_rbuf == NULL) {
5385a80dc5fSbsh /*
5395a80dc5fSbsh * Ring buffer allocation failed in the imxuart_attach_subr,
5405a80dc5fSbsh * only the tty is allocated, and nothing else.
5415a80dc5fSbsh */
5422626d576Srmind tty_free(sc->sc_tty);
543825088edSmatt return 0;
544825088edSmatt }
545825088edSmatt
5465a80dc5fSbsh /* Free the receive buffer. */
54745a935baSthorpej kmem_free(sc->sc_rbuf, sizeof(*sc->sc_rbuf) * sc->sc_rbuf_size);
5485a80dc5fSbsh
5495a80dc5fSbsh /* Detach and free the tty. */
5505a80dc5fSbsh tty_detach(sc->sc_tty);
5512626d576Srmind tty_free(sc->sc_tty);
5525a80dc5fSbsh
5535a80dc5fSbsh /* Unhook the soft interrupt handler. */
5545a80dc5fSbsh softint_disestablish(sc->sc_si);
5555a80dc5fSbsh
5567b0b7dedStls #ifdef RND_COM
5575a80dc5fSbsh /* Unhook the entropy source. */
5585a80dc5fSbsh rnd_detach_source(&sc->rnd_source);
5595a80dc5fSbsh #endif
5605a80dc5fSbsh callout_destroy(&sc->sc_diag_callout);
5615a80dc5fSbsh
5625a80dc5fSbsh /* Destroy the lock. */
5635a80dc5fSbsh mutex_destroy(&sc->sc_lock);
5645a80dc5fSbsh
5655a80dc5fSbsh return (0);
5665a80dc5fSbsh }
5675a80dc5fSbsh #endif
5685a80dc5fSbsh
5695a80dc5fSbsh #ifdef notyet
5705a80dc5fSbsh int
imxuart_activate(device_t self,enum devact act)5715a80dc5fSbsh imxuart_activate(device_t self, enum devact act)
572825088edSmatt {
5735a80dc5fSbsh struct imxuart_softc *sc = device_private(self);
5745a80dc5fSbsh int rv = 0;
5755a80dc5fSbsh
5765a80dc5fSbsh switch (act) {
5775a80dc5fSbsh case DVACT_ACTIVATE:
5785a80dc5fSbsh rv = EOPNOTSUPP;
5795a80dc5fSbsh break;
5805a80dc5fSbsh
5815a80dc5fSbsh case DVACT_DEACTIVATE:
5825a80dc5fSbsh if (sc->sc_hwflags & (IMXUART_HW_CONSOLE|IMXUART_HW_KGDB)) {
5835a80dc5fSbsh rv = EBUSY;
5845a80dc5fSbsh break;
585825088edSmatt }
586825088edSmatt
5875a80dc5fSbsh if (sc->disable != NULL && sc->enabled != 0) {
5885a80dc5fSbsh (*sc->disable)(sc);
5895a80dc5fSbsh sc->enabled = 0;
5905a80dc5fSbsh }
5915a80dc5fSbsh break;
5925a80dc5fSbsh }
5935a80dc5fSbsh
5945a80dc5fSbsh return (rv);
5955a80dc5fSbsh }
5965a80dc5fSbsh #endif
5975a80dc5fSbsh
598825088edSmatt void
imxuart_shutdown(struct imxuart_softc * sc)5995a80dc5fSbsh imxuart_shutdown(struct imxuart_softc *sc)
600825088edSmatt {
6015a80dc5fSbsh struct tty *tp = sc->sc_tty;
6025a80dc5fSbsh
6035a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
6045a80dc5fSbsh
6055a80dc5fSbsh /* If we were asserting flow control, then deassert it. */
6065a80dc5fSbsh SET(sc->sc_rx_flags, IMXUART_RX_IBUF_BLOCKED);
6075a80dc5fSbsh imxuart_hwiflow(sc);
6085a80dc5fSbsh
6095a80dc5fSbsh /* Clear any break condition set with TIOCSBRK. */
6105a80dc5fSbsh imxuart_break(sc, false);
6115a80dc5fSbsh
6125a80dc5fSbsh /*
6135a80dc5fSbsh * Hang up if necessary. Wait a bit, so the other side has time to
6145a80dc5fSbsh * notice even if we immediately open the port again.
6155a80dc5fSbsh * Avoid tsleeping above splhigh().
6165a80dc5fSbsh */
6175a80dc5fSbsh if (ISSET(tp->t_cflag, HUPCL)) {
6185a80dc5fSbsh imxuart_modem(sc, 0);
6195a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
6205a80dc5fSbsh /* XXX will only timeout */
6215a80dc5fSbsh (void) kpause(ttclos, false, hz, NULL);
6225a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
6235a80dc5fSbsh }
6245a80dc5fSbsh
6255a80dc5fSbsh /* Turn off interrupts. */
6265a80dc5fSbsh imxuart_disable_all_interrupts(sc);
6275a80dc5fSbsh /* re-enable recv interrupt for console or kgdb port */
6285a80dc5fSbsh imxuart_enable_debugport(sc);
6295a80dc5fSbsh
6305a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
6315a80dc5fSbsh
6325a80dc5fSbsh #ifdef notyet
6335a80dc5fSbsh if (sc->disable) {
6345a80dc5fSbsh #ifdef DIAGNOSTIC
6355a80dc5fSbsh if (!sc->enabled)
6365a80dc5fSbsh panic("imxuart_shutdown: not enabled?");
6375a80dc5fSbsh #endif
6385a80dc5fSbsh (*sc->disable)(sc);
6395a80dc5fSbsh sc->enabled = 0;
6405a80dc5fSbsh }
6415a80dc5fSbsh #endif
642825088edSmatt }
643825088edSmatt
644825088edSmatt int
imxuopen(dev_t dev,int flag,int mode,struct lwp * l)6455a80dc5fSbsh imxuopen(dev_t dev, int flag, int mode, struct lwp *l)
646825088edSmatt {
647825088edSmatt struct imxuart_softc *sc;
6485a80dc5fSbsh struct tty *tp;
6495a80dc5fSbsh int s;
6505a80dc5fSbsh int error;
651825088edSmatt
6525a80dc5fSbsh sc = device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
6535a80dc5fSbsh if (sc == NULL || !ISSET(sc->sc_hwflags, IMXUART_HW_DEV_OK) ||
6545a80dc5fSbsh sc->sc_rbuf == NULL)
6555a80dc5fSbsh return (ENXIO);
6565a80dc5fSbsh
6575a80dc5fSbsh if (!device_is_active(sc->sc_dev))
6585a80dc5fSbsh return (ENXIO);
6595a80dc5fSbsh
6605a80dc5fSbsh #ifdef KGDB
6615a80dc5fSbsh /*
6625a80dc5fSbsh * If this is the kgdb port, no other use is permitted.
6635a80dc5fSbsh */
6645a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_KGDB))
6655a80dc5fSbsh return (EBUSY);
6665a80dc5fSbsh #endif
6675a80dc5fSbsh
6685a80dc5fSbsh tp = sc->sc_tty;
6695a80dc5fSbsh
6705a80dc5fSbsh if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
6715a80dc5fSbsh return (EBUSY);
6725a80dc5fSbsh
6735a80dc5fSbsh s = spltty();
6745a80dc5fSbsh
6755a80dc5fSbsh /*
6765a80dc5fSbsh * Do the following iff this is a first open.
6775a80dc5fSbsh */
6785a80dc5fSbsh if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
6795a80dc5fSbsh struct termios t;
6805a80dc5fSbsh
6815a80dc5fSbsh tp->t_dev = dev;
6825a80dc5fSbsh
6835a80dc5fSbsh
6845a80dc5fSbsh #ifdef notyet
6855a80dc5fSbsh if (sc->enable) {
6865a80dc5fSbsh if ((*sc->enable)(sc)) {
6875a80dc5fSbsh splx(s);
6885a80dc5fSbsh aprint_error_dev(sc->sc_dev,
6895a80dc5fSbsh "device enable failed\n");
6905a80dc5fSbsh return (EIO);
6915a80dc5fSbsh }
6925a80dc5fSbsh sc->enabled = 1;
6935a80dc5fSbsh }
6945a80dc5fSbsh #endif
6955a80dc5fSbsh
6965a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
6975a80dc5fSbsh
6985a80dc5fSbsh imxuart_disable_all_interrupts(sc);
6995a80dc5fSbsh
7005a80dc5fSbsh /* Fetch the current modem control status, needed later. */
7015a80dc5fSbsh
7025a80dc5fSbsh #ifdef IMXUART_PPS
7035a80dc5fSbsh /* Clear PPS capture state on first open. */
7045a80dc5fSbsh mutex_spin_enter(&timecounter_lock);
7055a80dc5fSbsh memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state));
7065a80dc5fSbsh sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT | PPS_CAPTURECLEAR;
7075a80dc5fSbsh pps_init(&sc->sc_pps_state);
7085a80dc5fSbsh mutex_spin_exit(&timecounter_lock);
7095a80dc5fSbsh #endif
7105a80dc5fSbsh
7115a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
7125a80dc5fSbsh
7135a80dc5fSbsh /*
7145a80dc5fSbsh * Initialize the termios status to the defaults. Add in the
7155a80dc5fSbsh * sticky bits from TIOCSFLAGS.
7165a80dc5fSbsh */
7175a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_CONSOLE)) {
7185a80dc5fSbsh t.c_ospeed = imxuconsrate;
7195a80dc5fSbsh t.c_cflag = imxuconscflag;
7205a80dc5fSbsh } else {
7215a80dc5fSbsh t.c_ospeed = TTYDEF_SPEED;
7225a80dc5fSbsh t.c_cflag = TTYDEF_CFLAG;
7235a80dc5fSbsh }
7245a80dc5fSbsh t.c_ispeed = t.c_ospeed;
7255a80dc5fSbsh if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
7265a80dc5fSbsh SET(t.c_cflag, CLOCAL);
7275a80dc5fSbsh if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
7285a80dc5fSbsh SET(t.c_cflag, CRTSCTS);
7295a80dc5fSbsh if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
7305a80dc5fSbsh SET(t.c_cflag, MDMBUF);
7315a80dc5fSbsh /* Make sure imxuparam() will do something. */
7325a80dc5fSbsh tp->t_ospeed = 0;
7335a80dc5fSbsh (void) imxuparam(tp, &t);
7345a80dc5fSbsh tp->t_iflag = TTYDEF_IFLAG;
7355a80dc5fSbsh tp->t_oflag = TTYDEF_OFLAG;
7365a80dc5fSbsh tp->t_lflag = TTYDEF_LFLAG;
7375a80dc5fSbsh ttychars(tp);
7385a80dc5fSbsh ttsetwater(tp);
7395a80dc5fSbsh
7405a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
7415a80dc5fSbsh
7425a80dc5fSbsh /*
7435a80dc5fSbsh * Turn on DTR. We must always do this, even if carrier is not
7445a80dc5fSbsh * present, because otherwise we'd have to use TIOCSDTR
7455a80dc5fSbsh * immediately after setting CLOCAL, which applications do not
7465a80dc5fSbsh * expect. We always assert DTR while the device is open
7475a80dc5fSbsh * unless explicitly requested to deassert it.
7485a80dc5fSbsh */
7495a80dc5fSbsh imxuart_modem(sc, 1);
7505a80dc5fSbsh
7515a80dc5fSbsh /* Clear the input ring, and unblock. */
7525a80dc5fSbsh sc->sc_rbuf_in = sc->sc_rbuf_out = 0;
7535a80dc5fSbsh imxuart_iflush(sc);
7545a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_ANY_BLOCK);
7555a80dc5fSbsh imxuart_hwiflow(sc);
7565a80dc5fSbsh
7575a80dc5fSbsh /* Turn on interrupts. */
7585a80dc5fSbsh imxuart_control_rxint(sc, true);
7595a80dc5fSbsh
7605a80dc5fSbsh #ifdef IMXUART_DEBUG
7615a80dc5fSbsh if (imxuart_debug)
7625a80dc5fSbsh imxustatus(sc, "imxuopen ");
7635a80dc5fSbsh #endif
7645a80dc5fSbsh
7655a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
766825088edSmatt }
767825088edSmatt
7685a80dc5fSbsh splx(s);
7695a80dc5fSbsh
7705a80dc5fSbsh #if 0
7715a80dc5fSbsh error = ttyopen(tp, IMXUART_DIALOUT(dev), ISSET(flag, O_NONBLOCK));
7725a80dc5fSbsh #else
7735a80dc5fSbsh error = ttyopen(tp, 1, ISSET(flag, O_NONBLOCK));
7745a80dc5fSbsh #endif
7755a80dc5fSbsh if (error)
7765a80dc5fSbsh goto bad;
7775a80dc5fSbsh
7785a80dc5fSbsh error = (*tp->t_linesw->l_open)(dev, tp);
7795a80dc5fSbsh if (error)
7805a80dc5fSbsh goto bad;
7815a80dc5fSbsh
7825a80dc5fSbsh return (0);
7835a80dc5fSbsh
7845a80dc5fSbsh bad:
7855a80dc5fSbsh if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
7865a80dc5fSbsh /*
7875a80dc5fSbsh * We failed to open the device, and nobody else had it opened.
7885a80dc5fSbsh * Clean up the state as appropriate.
7895a80dc5fSbsh */
7905a80dc5fSbsh imxuart_shutdown(sc);
791825088edSmatt }
792825088edSmatt
7935a80dc5fSbsh return (error);
794825088edSmatt }
7955a80dc5fSbsh
796825088edSmatt int
imxuclose(dev_t dev,int flag,int mode,struct lwp * l)7975a80dc5fSbsh imxuclose(dev_t dev, int flag, int mode, struct lwp *l)
798825088edSmatt {
7995a80dc5fSbsh struct imxuart_softc *sc =
8005a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8015a80dc5fSbsh struct tty *tp = sc->sc_tty;
8025a80dc5fSbsh
8035a80dc5fSbsh /* XXX This is for cons.c. */
8045a80dc5fSbsh if (!ISSET(tp->t_state, TS_ISOPEN))
8055a80dc5fSbsh return (0);
8065a80dc5fSbsh
8075a80dc5fSbsh (*tp->t_linesw->l_close)(tp, flag);
8085a80dc5fSbsh ttyclose(tp);
8095a80dc5fSbsh
8105a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
8115a80dc5fSbsh return (0);
8125a80dc5fSbsh
8135a80dc5fSbsh if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
8145a80dc5fSbsh /*
8155a80dc5fSbsh * Although we got a last close, the device may still be in
8165a80dc5fSbsh * use; e.g. if this was the dialout node, and there are still
8175a80dc5fSbsh * processes waiting for carrier on the non-dialout node.
8185a80dc5fSbsh */
8195a80dc5fSbsh imxuart_shutdown(sc);
8205a80dc5fSbsh }
8215a80dc5fSbsh
8225a80dc5fSbsh return (0);
8235a80dc5fSbsh }
8245a80dc5fSbsh
8255a80dc5fSbsh int
imxuread(dev_t dev,struct uio * uio,int flag)8265a80dc5fSbsh imxuread(dev_t dev, struct uio *uio, int flag)
8275a80dc5fSbsh {
8285a80dc5fSbsh struct imxuart_softc *sc =
8295a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8305a80dc5fSbsh struct tty *tp = sc->sc_tty;
8315a80dc5fSbsh
8325a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
8335a80dc5fSbsh return (EIO);
8345a80dc5fSbsh
8355a80dc5fSbsh return ((*tp->t_linesw->l_read)(tp, uio, flag));
8365a80dc5fSbsh }
8375a80dc5fSbsh
8385a80dc5fSbsh int
imxuwrite(dev_t dev,struct uio * uio,int flag)8395a80dc5fSbsh imxuwrite(dev_t dev, struct uio *uio, int flag)
8405a80dc5fSbsh {
8415a80dc5fSbsh struct imxuart_softc *sc =
8425a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8435a80dc5fSbsh struct tty *tp = sc->sc_tty;
8445a80dc5fSbsh
8455a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
8465a80dc5fSbsh return (EIO);
8475a80dc5fSbsh
8485a80dc5fSbsh return ((*tp->t_linesw->l_write)(tp, uio, flag));
8495a80dc5fSbsh }
8505a80dc5fSbsh
8515a80dc5fSbsh int
imxupoll(dev_t dev,int events,struct lwp * l)8525a80dc5fSbsh imxupoll(dev_t dev, int events, struct lwp *l)
8535a80dc5fSbsh {
8545a80dc5fSbsh struct imxuart_softc *sc =
8555a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8565a80dc5fSbsh struct tty *tp = sc->sc_tty;
8575a80dc5fSbsh
8585a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
8595a80dc5fSbsh return (POLLHUP);
8605a80dc5fSbsh
8615a80dc5fSbsh return ((*tp->t_linesw->l_poll)(tp, events, l));
8625a80dc5fSbsh }
8635a80dc5fSbsh
8645a80dc5fSbsh struct tty *
imxutty(dev_t dev)8655a80dc5fSbsh imxutty(dev_t dev)
8665a80dc5fSbsh {
8675a80dc5fSbsh struct imxuart_softc *sc =
8685a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8695a80dc5fSbsh struct tty *tp = sc->sc_tty;
8705a80dc5fSbsh
8715a80dc5fSbsh return (tp);
8725a80dc5fSbsh }
8735a80dc5fSbsh
8745a80dc5fSbsh int
imxuioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)8755a80dc5fSbsh imxuioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
8765a80dc5fSbsh {
8775a80dc5fSbsh struct imxuart_softc *sc;
8785a80dc5fSbsh struct tty *tp;
8795a80dc5fSbsh int error;
8805a80dc5fSbsh
8815a80dc5fSbsh sc = device_lookup_private(&imxuart_cd, IMXUART_UNIT(dev));
8825a80dc5fSbsh if (sc == NULL)
8835a80dc5fSbsh return ENXIO;
8845a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
8855a80dc5fSbsh return (EIO);
8865a80dc5fSbsh
8875a80dc5fSbsh tp = sc->sc_tty;
8885a80dc5fSbsh
8895a80dc5fSbsh error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
8905a80dc5fSbsh if (error != EPASSTHROUGH)
8915a80dc5fSbsh return (error);
8925a80dc5fSbsh
8935a80dc5fSbsh error = ttioctl(tp, cmd, data, flag, l);
8945a80dc5fSbsh if (error != EPASSTHROUGH)
8955a80dc5fSbsh return (error);
8965a80dc5fSbsh
8975a80dc5fSbsh error = 0;
8985a80dc5fSbsh switch (cmd) {
8995a80dc5fSbsh case TIOCSFLAGS:
9005a80dc5fSbsh error = kauth_authorize_device_tty(l->l_cred,
9015a80dc5fSbsh KAUTH_DEVICE_TTY_PRIVSET, tp);
9025a80dc5fSbsh break;
9035a80dc5fSbsh default:
9045a80dc5fSbsh /* nothing */
9055a80dc5fSbsh break;
9065a80dc5fSbsh }
9075a80dc5fSbsh if (error) {
9085a80dc5fSbsh return error;
9095a80dc5fSbsh }
9105a80dc5fSbsh
9115a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
9125a80dc5fSbsh
9135a80dc5fSbsh switch (cmd) {
9145a80dc5fSbsh case TIOCSBRK:
9155a80dc5fSbsh imxuart_break(sc, true);
9165a80dc5fSbsh break;
9175a80dc5fSbsh
9185a80dc5fSbsh case TIOCCBRK:
9195a80dc5fSbsh imxuart_break(sc, false);
9205a80dc5fSbsh break;
9215a80dc5fSbsh
9225a80dc5fSbsh case TIOCSDTR:
9235a80dc5fSbsh imxuart_modem(sc, 1);
9245a80dc5fSbsh break;
9255a80dc5fSbsh
9265a80dc5fSbsh case TIOCCDTR:
9275a80dc5fSbsh imxuart_modem(sc, 0);
9285a80dc5fSbsh break;
9295a80dc5fSbsh
9305a80dc5fSbsh case TIOCGFLAGS:
9315a80dc5fSbsh *(int *)data = sc->sc_swflags;
9325a80dc5fSbsh break;
9335a80dc5fSbsh
9345a80dc5fSbsh case TIOCSFLAGS:
9355a80dc5fSbsh sc->sc_swflags = *(int *)data;
9365a80dc5fSbsh break;
9375a80dc5fSbsh
9385a80dc5fSbsh case TIOCMSET:
9395a80dc5fSbsh case TIOCMBIS:
9405a80dc5fSbsh case TIOCMBIC:
9415a80dc5fSbsh tiocm_to_imxu(sc, cmd, *(int *)data);
9425a80dc5fSbsh break;
9435a80dc5fSbsh
9445a80dc5fSbsh case TIOCMGET:
9455a80dc5fSbsh *(int *)data = imxuart_to_tiocm(sc);
9465a80dc5fSbsh break;
9475a80dc5fSbsh
9485a80dc5fSbsh #ifdef notyet
9495a80dc5fSbsh case PPS_IOC_CREATE:
9505a80dc5fSbsh case PPS_IOC_DESTROY:
9515a80dc5fSbsh case PPS_IOC_GETPARAMS:
9525a80dc5fSbsh case PPS_IOC_SETPARAMS:
9535a80dc5fSbsh case PPS_IOC_GETCAP:
9545a80dc5fSbsh case PPS_IOC_FETCH:
9555a80dc5fSbsh #ifdef PPS_SYNC
9565a80dc5fSbsh case PPS_IOC_KCBIND:
9575a80dc5fSbsh #endif
9585a80dc5fSbsh mutex_spin_enter(&timecounter_lock);
9595a80dc5fSbsh error = pps_ioctl(cmd, data, &sc->sc_pps_state);
9605a80dc5fSbsh mutex_spin_exit(&timecounter_lock);
9615a80dc5fSbsh break;
9625a80dc5fSbsh
9635a80dc5fSbsh case TIOCDCDTIMESTAMP: /* XXX old, overloaded API used by xntpd v3 */
9645a80dc5fSbsh mutex_spin_enter(&timecounter_lock);
9655a80dc5fSbsh #ifndef PPS_TRAILING_EDGE
9665a80dc5fSbsh TIMESPEC_TO_TIMEVAL((struct timeval *)data,
9675a80dc5fSbsh &sc->sc_pps_state.ppsinfo.assert_timestamp);
9685a80dc5fSbsh #else
9695a80dc5fSbsh TIMESPEC_TO_TIMEVAL((struct timeval *)data,
9705a80dc5fSbsh &sc->sc_pps_state.ppsinfo.clear_timestamp);
9715a80dc5fSbsh #endif
9725a80dc5fSbsh mutex_spin_exit(&timecounter_lock);
9735a80dc5fSbsh break;
9745a80dc5fSbsh #endif
9755a80dc5fSbsh
9765a80dc5fSbsh default:
9775a80dc5fSbsh error = EPASSTHROUGH;
9785a80dc5fSbsh break;
9795a80dc5fSbsh }
9805a80dc5fSbsh
9815a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
9825a80dc5fSbsh
9835a80dc5fSbsh #ifdef IMXUART_DEBUG
9845a80dc5fSbsh if (imxuart_debug)
9855a80dc5fSbsh imxustatus(sc, "imxuioctl ");
9865a80dc5fSbsh #endif
9875a80dc5fSbsh
9885a80dc5fSbsh return (error);
9895a80dc5fSbsh }
9905a80dc5fSbsh
9915a80dc5fSbsh integrate void
imxuart_schedrx(struct imxuart_softc * sc)9925a80dc5fSbsh imxuart_schedrx(struct imxuart_softc *sc)
9935a80dc5fSbsh {
9945a80dc5fSbsh sc->sc_rx_ready = 1;
9955a80dc5fSbsh
9965a80dc5fSbsh /* Wake up the poller. */
9975a80dc5fSbsh softint_schedule(sc->sc_si);
9985a80dc5fSbsh }
9995a80dc5fSbsh
10005a80dc5fSbsh void
imxuart_break(struct imxuart_softc * sc,bool onoff)10015a80dc5fSbsh imxuart_break(struct imxuart_softc *sc, bool onoff)
10025a80dc5fSbsh {
10035a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
10045a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
10055a80dc5fSbsh
10065a80dc5fSbsh if (onoff)
10075a80dc5fSbsh SET(sc->sc_ucr1, IMX_UCR1_SNDBRK);
10085a80dc5fSbsh else
10095a80dc5fSbsh CLR(sc->sc_ucr1, IMX_UCR1_SNDBRK);
10105a80dc5fSbsh
10115a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR1, sc->sc_ucr1);
10125a80dc5fSbsh }
10135a80dc5fSbsh
10145a80dc5fSbsh void
imxuart_modem(struct imxuart_softc * sc,int onoff)10155a80dc5fSbsh imxuart_modem(struct imxuart_softc *sc, int onoff)
10165a80dc5fSbsh {
10175a80dc5fSbsh #ifdef notyet
10185a80dc5fSbsh if (sc->sc_mcr_dtr == 0)
10195a80dc5fSbsh return;
10205a80dc5fSbsh
10215a80dc5fSbsh if (onoff)
10225a80dc5fSbsh SET(sc->sc_mcr, sc->sc_mcr_dtr);
10235a80dc5fSbsh else
10245a80dc5fSbsh CLR(sc->sc_mcr, sc->sc_mcr_dtr);
10255a80dc5fSbsh
10265a80dc5fSbsh if (!sc->sc_heldchange) {
10275a80dc5fSbsh if (sc->sc_tx_busy) {
10285a80dc5fSbsh sc->sc_heldtbc = sc->sc_tbc;
10295a80dc5fSbsh sc->sc_tbc = 0;
10305a80dc5fSbsh sc->sc_heldchange = 1;
10315a80dc5fSbsh } else
10325a80dc5fSbsh imxuart_loadchannelregs(sc);
10335a80dc5fSbsh }
10345a80dc5fSbsh #endif
10355a80dc5fSbsh }
10365a80dc5fSbsh
10375a80dc5fSbsh /*
10385a80dc5fSbsh * RTS output is controlled by UCR2.CTS bit.
10395a80dc5fSbsh * DTR output is controlled by UCR3.DSR bit.
10405a80dc5fSbsh * (i.MX reference manual uses names in DCE mode)
10415a80dc5fSbsh *
10425a80dc5fSbsh * note: if UCR2.CTSC == 1 for automatic HW flow control, UCR2.CTS is ignored.
10435a80dc5fSbsh */
10445a80dc5fSbsh void
tiocm_to_imxu(struct imxuart_softc * sc,u_long how,int ttybits)10455a80dc5fSbsh tiocm_to_imxu(struct imxuart_softc *sc, u_long how, int ttybits)
10465a80dc5fSbsh {
10475a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
10485a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
10495a80dc5fSbsh
10505a80dc5fSbsh uint32_t ucr2 = sc->sc_ucr2_d;
10515a80dc5fSbsh uint32_t ucr3 = sc->sc_ucr3;
10525a80dc5fSbsh
10535a80dc5fSbsh uint32_t ucr2_mask = 0;
10545a80dc5fSbsh uint32_t ucr3_mask = 0;
10555a80dc5fSbsh
10565a80dc5fSbsh
10575a80dc5fSbsh if (ISSET(ttybits, TIOCM_DTR))
10585a80dc5fSbsh ucr3_mask = IMX_UCR3_DSR;
10595a80dc5fSbsh if (ISSET(ttybits, TIOCM_RTS))
10605a80dc5fSbsh ucr2_mask = IMX_UCR2_CTS;
10615a80dc5fSbsh
10625a80dc5fSbsh switch (how) {
10635a80dc5fSbsh case TIOCMBIC:
10645a80dc5fSbsh CLR(ucr2, ucr2_mask);
10655a80dc5fSbsh CLR(ucr3, ucr3_mask);
10665a80dc5fSbsh break;
10675a80dc5fSbsh
10685a80dc5fSbsh case TIOCMBIS:
10695a80dc5fSbsh SET(ucr2, ucr2_mask);
10705a80dc5fSbsh SET(ucr3, ucr3_mask);
10715a80dc5fSbsh break;
10725a80dc5fSbsh
10735a80dc5fSbsh case TIOCMSET:
10745a80dc5fSbsh CLR(ucr2, ucr2_mask);
10755a80dc5fSbsh CLR(ucr3, ucr3_mask);
10765a80dc5fSbsh SET(ucr2, ucr2_mask);
10775a80dc5fSbsh SET(ucr3, ucr3_mask);
10785a80dc5fSbsh break;
10795a80dc5fSbsh }
10805a80dc5fSbsh
10815a80dc5fSbsh if (ucr3 != sc->sc_ucr3) {
10825a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR3, ucr3);
10835a80dc5fSbsh sc->sc_ucr3 = ucr3;
10845a80dc5fSbsh }
10855a80dc5fSbsh
10865a80dc5fSbsh if (ucr2 == sc->sc_ucr2_d)
10875a80dc5fSbsh return;
10885a80dc5fSbsh
10895a80dc5fSbsh sc->sc_ucr2_d = ucr2;
10905a80dc5fSbsh /* update CTS bit only */
10915a80dc5fSbsh ucr2 = (sc->sc_ucr2 & ~IMX_UCR2_CTS) |
10925a80dc5fSbsh (ucr2 & IMX_UCR2_CTS);
10935a80dc5fSbsh
10945a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR2, ucr2);
10955a80dc5fSbsh sc->sc_ucr2 = ucr2;
10965a80dc5fSbsh }
10975a80dc5fSbsh
10985a80dc5fSbsh int
imxuart_to_tiocm(struct imxuart_softc * sc)10995a80dc5fSbsh imxuart_to_tiocm(struct imxuart_softc *sc)
11005a80dc5fSbsh {
11015a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
11025a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
11035a80dc5fSbsh int ttybits = 0;
11045a80dc5fSbsh uint32_t usr[2];
11055a80dc5fSbsh
11065a80dc5fSbsh if (ISSET(sc->sc_ucr3, IMX_UCR3_DSR))
11075a80dc5fSbsh SET(ttybits, TIOCM_DTR);
11085a80dc5fSbsh if (ISSET(sc->sc_ucr2, IMX_UCR2_CTS))
11095a80dc5fSbsh SET(ttybits, TIOCM_RTS);
11105a80dc5fSbsh
11115a80dc5fSbsh bus_space_read_region_4(iot, ioh, IMX_USR1, usr, 2);
11125a80dc5fSbsh
11135a80dc5fSbsh if (ISSET(usr[0], IMX_USR1_RTSS))
11145a80dc5fSbsh SET(ttybits, TIOCM_CTS);
11155a80dc5fSbsh
11165a80dc5fSbsh if (ISSET(usr[1], IMX_USR2_DCDIN))
11175a80dc5fSbsh SET(ttybits, TIOCM_CD);
11185a80dc5fSbsh
11195a80dc5fSbsh #if 0
11205a80dc5fSbsh /* XXXbsh: I couldn't find the way to read ipp_uart_dsr_dte_i signal,
11215a80dc5fSbsh although there are bits in UART registers to detect delta of DSR.
11225a80dc5fSbsh */
11235a80dc5fSbsh if (ISSET(imxubits, MSR_DSR))
11245a80dc5fSbsh SET(ttybits, TIOCM_DSR);
11255a80dc5fSbsh #endif
11265a80dc5fSbsh
11275a80dc5fSbsh if (ISSET(usr[1], IMX_USR2_RIIN))
11285a80dc5fSbsh SET(ttybits, TIOCM_RI);
11295a80dc5fSbsh
11305a80dc5fSbsh
11315a80dc5fSbsh #ifdef notyet
11325a80dc5fSbsh if (ISSET(sc->sc_ier, IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC))
11335a80dc5fSbsh SET(ttybits, TIOCM_LE);
11345a80dc5fSbsh #endif
11355a80dc5fSbsh
11365a80dc5fSbsh return (ttybits);
11375a80dc5fSbsh }
11385a80dc5fSbsh
11395a80dc5fSbsh static uint32_t
cflag_to_ucr2(tcflag_t cflag,uint32_t oldval)11405a80dc5fSbsh cflag_to_ucr2(tcflag_t cflag, uint32_t oldval)
11415a80dc5fSbsh {
11425a80dc5fSbsh uint32_t val = oldval;
11435a80dc5fSbsh
11445a80dc5fSbsh CLR(val,IMX_UCR2_WS|IMX_UCR2_PREN|IMX_UCR2_PROE|IMX_UCR2_STPB);
11455a80dc5fSbsh
11465a80dc5fSbsh switch (cflag & CSIZE) {
11475a80dc5fSbsh case CS5:
11485a80dc5fSbsh case CS6:
11495a80dc5fSbsh /* not suppreted. use 7-bits */
11505a80dc5fSbsh case CS7:
11515a80dc5fSbsh break;
11525a80dc5fSbsh case CS8:
11535a80dc5fSbsh SET(val, IMX_UCR2_WS);
11545a80dc5fSbsh break;
11555a80dc5fSbsh }
11565a80dc5fSbsh
11575a80dc5fSbsh
11585a80dc5fSbsh if (ISSET(cflag, PARENB)) {
11595a80dc5fSbsh SET(val, IMX_UCR2_PREN);
11605a80dc5fSbsh
11615a80dc5fSbsh /* odd parity */
11625a80dc5fSbsh if (!ISSET(cflag, PARODD))
11635a80dc5fSbsh SET(val, IMX_UCR2_PROE);
11645a80dc5fSbsh }
11655a80dc5fSbsh
11665a80dc5fSbsh if (ISSET(cflag, CSTOPB))
11675a80dc5fSbsh SET(val, IMX_UCR2_STPB);
11685a80dc5fSbsh
11695a80dc5fSbsh val |= IMX_UCR2_TXEN| IMX_UCR2_RXEN|IMX_UCR2_SRST;
11705a80dc5fSbsh
11715a80dc5fSbsh return val;
11725a80dc5fSbsh }
11735a80dc5fSbsh
11745a80dc5fSbsh int
imxuparam(struct tty * tp,struct termios * t)11755a80dc5fSbsh imxuparam(struct tty *tp, struct termios *t)
11765a80dc5fSbsh {
11775a80dc5fSbsh struct imxuart_softc *sc =
11785a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(tp->t_dev));
11795a80dc5fSbsh struct imxuart_baudrate_ratio ratio;
11805a80dc5fSbsh uint32_t ucr2;
11815a80dc5fSbsh bool change_speed = tp->t_ospeed != t->c_ospeed;
11825a80dc5fSbsh
11835a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
11845a80dc5fSbsh return (EIO);
11855a80dc5fSbsh
11865a80dc5fSbsh /* Check requested parameters. */
11875a80dc5fSbsh if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
11885a80dc5fSbsh return (EINVAL);
11895a80dc5fSbsh
11905a80dc5fSbsh /*
11915a80dc5fSbsh * For the console, always force CLOCAL and !HUPCL, so that the port
11925a80dc5fSbsh * is always active.
11935a80dc5fSbsh */
11945a80dc5fSbsh if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
11955a80dc5fSbsh ISSET(sc->sc_hwflags, IMXUART_HW_CONSOLE)) {
11965a80dc5fSbsh SET(t->c_cflag, CLOCAL);
11975a80dc5fSbsh CLR(t->c_cflag, HUPCL);
11985a80dc5fSbsh }
11995a80dc5fSbsh
12005a80dc5fSbsh /*
12015a80dc5fSbsh * If there were no changes, don't do anything. This avoids dropping
12025a80dc5fSbsh * input and improves performance when all we did was frob things like
12035a80dc5fSbsh * VMIN and VTIME.
12045a80dc5fSbsh */
12055a80dc5fSbsh if ( !change_speed && tp->t_cflag == t->c_cflag)
12065a80dc5fSbsh return (0);
12075a80dc5fSbsh
12085a80dc5fSbsh if (change_speed) {
12095a80dc5fSbsh /* calculate baudrate modulator value */
12105a80dc5fSbsh if (imxuspeed(t->c_ospeed, &ratio) < 0)
12115a80dc5fSbsh return (EINVAL);
12125a80dc5fSbsh sc->sc_ratio = ratio;
12135a80dc5fSbsh }
12145a80dc5fSbsh
12155a80dc5fSbsh ucr2 = cflag_to_ucr2(t->c_cflag, sc->sc_ucr2_d);
12165a80dc5fSbsh
12175a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
12185a80dc5fSbsh
12195a80dc5fSbsh #if 0 /* flow control stuff. not yet */
12205a80dc5fSbsh /*
12215a80dc5fSbsh * If we're not in a mode that assumes a connection is present, then
12225a80dc5fSbsh * ignore carrier changes.
12235a80dc5fSbsh */
12245a80dc5fSbsh if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
12255a80dc5fSbsh sc->sc_msr_dcd = 0;
12265a80dc5fSbsh else
12275a80dc5fSbsh sc->sc_msr_dcd = MSR_DCD;
12285a80dc5fSbsh /*
12295a80dc5fSbsh * Set the flow control pins depending on the current flow control
12305a80dc5fSbsh * mode.
12315a80dc5fSbsh */
12325a80dc5fSbsh if (ISSET(t->c_cflag, CRTSCTS)) {
12335a80dc5fSbsh sc->sc_mcr_dtr = MCR_DTR;
12345a80dc5fSbsh sc->sc_mcr_rts = MCR_RTS;
12355a80dc5fSbsh sc->sc_msr_cts = MSR_CTS;
12365a80dc5fSbsh sc->sc_efr = EFR_AUTORTS | EFR_AUTOCTS;
12375a80dc5fSbsh } else if (ISSET(t->c_cflag, MDMBUF)) {
12385a80dc5fSbsh /*
12395a80dc5fSbsh * For DTR/DCD flow control, make sure we don't toggle DTR for
12405a80dc5fSbsh * carrier detection.
12415a80dc5fSbsh */
12425a80dc5fSbsh sc->sc_mcr_dtr = 0;
12435a80dc5fSbsh sc->sc_mcr_rts = MCR_DTR;
12445a80dc5fSbsh sc->sc_msr_cts = MSR_DCD;
12455a80dc5fSbsh sc->sc_efr = 0;
12465a80dc5fSbsh } else {
12475a80dc5fSbsh /*
12485a80dc5fSbsh * If no flow control, then always set RTS. This will make
12495a80dc5fSbsh * the other side happy if it mistakenly thinks we're doing
12505a80dc5fSbsh * RTS/CTS flow control.
12515a80dc5fSbsh */
12525a80dc5fSbsh sc->sc_mcr_dtr = MCR_DTR | MCR_RTS;
12535a80dc5fSbsh sc->sc_mcr_rts = 0;
12545a80dc5fSbsh sc->sc_msr_cts = 0;
12555a80dc5fSbsh sc->sc_efr = 0;
12565a80dc5fSbsh if (ISSET(sc->sc_mcr, MCR_DTR))
12575a80dc5fSbsh SET(sc->sc_mcr, MCR_RTS);
12585a80dc5fSbsh else
12595a80dc5fSbsh CLR(sc->sc_mcr, MCR_RTS);
12605a80dc5fSbsh }
12615a80dc5fSbsh sc->sc_msr_mask = sc->sc_msr_cts | sc->sc_msr_dcd;
12625a80dc5fSbsh #endif
12635a80dc5fSbsh
12645a80dc5fSbsh /* And copy to tty. */
12655a80dc5fSbsh tp->t_ispeed = t->c_ospeed;
12665a80dc5fSbsh tp->t_ospeed = t->c_ospeed;
12675a80dc5fSbsh tp->t_cflag = t->c_cflag;
12685a80dc5fSbsh
12695a80dc5fSbsh if (!change_speed && ucr2 == sc->sc_ucr2_d) {
12705a80dc5fSbsh /* noop */
12715a80dc5fSbsh }
12725a80dc5fSbsh else if (!sc->sc_pending && !sc->sc_tx_busy) {
12735a80dc5fSbsh if (ucr2 != sc->sc_ucr2_d) {
12745a80dc5fSbsh sc->sc_ucr2_d = ucr2;
12755a80dc5fSbsh imxuart_load_params(sc);
12765a80dc5fSbsh }
12775a80dc5fSbsh if (change_speed)
12785a80dc5fSbsh imxuart_load_speed(sc);
12795a80dc5fSbsh }
12805a80dc5fSbsh else {
12815a80dc5fSbsh if (!sc->sc_pending) {
12825a80dc5fSbsh sc->sc_heldtbc = sc->sc_tbc;
12835a80dc5fSbsh sc->sc_tbc = 0;
12845a80dc5fSbsh }
12855a80dc5fSbsh sc->sc_pending |=
12865a80dc5fSbsh (ucr2 == sc->sc_ucr2_d ? 0 : IMXUART_PEND_PARAM) |
12875a80dc5fSbsh (change_speed ? 0 : IMXUART_PEND_SPEED);
12885a80dc5fSbsh sc->sc_ucr2_d = ucr2;
12895a80dc5fSbsh }
12905a80dc5fSbsh
12915a80dc5fSbsh if (!ISSET(t->c_cflag, CHWFLOW)) {
12925a80dc5fSbsh /* Disable the high water mark. */
12935a80dc5fSbsh sc->sc_r_hiwat = 0;
12945a80dc5fSbsh sc->sc_r_lowat = 0;
12955a80dc5fSbsh if (ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED)) {
12965a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED);
12975a80dc5fSbsh imxuart_schedrx(sc);
12985a80dc5fSbsh }
12995a80dc5fSbsh if (ISSET(sc->sc_rx_flags,
13005a80dc5fSbsh IMXUART_RX_TTY_BLOCKED|IMXUART_RX_IBUF_BLOCKED)) {
13015a80dc5fSbsh CLR(sc->sc_rx_flags,
13025a80dc5fSbsh IMXUART_RX_TTY_BLOCKED|IMXUART_RX_IBUF_BLOCKED);
13035a80dc5fSbsh imxuart_hwiflow(sc);
13045a80dc5fSbsh }
13055a80dc5fSbsh } else {
13065a80dc5fSbsh sc->sc_r_hiwat = imxuart_rbuf_hiwat;
13075a80dc5fSbsh sc->sc_r_lowat = imxuart_rbuf_lowat;
13085a80dc5fSbsh }
13095a80dc5fSbsh
13105a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
13115a80dc5fSbsh
13125a80dc5fSbsh #if 0
13135a80dc5fSbsh /*
13145a80dc5fSbsh * Update the tty layer's idea of the carrier bit, in case we changed
13155a80dc5fSbsh * CLOCAL or MDMBUF. We don't hang up here; we only do that by
13165a80dc5fSbsh * explicit request.
13175a80dc5fSbsh */
13185a80dc5fSbsh (void) (*tp->t_linesw->l_modem)(tp, ISSET(sc->sc_msr, MSR_DCD));
13195a80dc5fSbsh #else
13205a80dc5fSbsh /* XXX: always report that we have DCD */
13215a80dc5fSbsh (void) (*tp->t_linesw->l_modem)(tp, 1);
13225a80dc5fSbsh #endif
13235a80dc5fSbsh
13245a80dc5fSbsh #ifdef IMXUART_DEBUG
13255a80dc5fSbsh if (imxuart_debug)
13265a80dc5fSbsh imxustatus(sc, "imxuparam ");
13275a80dc5fSbsh #endif
13285a80dc5fSbsh
13295a80dc5fSbsh if (!ISSET(t->c_cflag, CHWFLOW)) {
13305a80dc5fSbsh if (sc->sc_tx_stopped) {
13315a80dc5fSbsh sc->sc_tx_stopped = 0;
13325a80dc5fSbsh imxustart(tp);
13335a80dc5fSbsh }
13345a80dc5fSbsh }
13355a80dc5fSbsh
13365a80dc5fSbsh return (0);
13375a80dc5fSbsh }
13385a80dc5fSbsh
13395a80dc5fSbsh void
imxuart_iflush(struct imxuart_softc * sc)13405a80dc5fSbsh imxuart_iflush(struct imxuart_softc *sc)
13415a80dc5fSbsh {
13425a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
13435a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
13445a80dc5fSbsh #ifdef DIAGNOSTIC
13455a80dc5fSbsh uint32_t reg = 0xffff;
13465a80dc5fSbsh #endif
13475a80dc5fSbsh int timo;
13485a80dc5fSbsh
13495a80dc5fSbsh timo = 50000;
13505a80dc5fSbsh /* flush any pending I/O */
13515a80dc5fSbsh while (ISSET(bus_space_read_4(iot, ioh, IMX_USR2), IMX_USR2_RDR)
13525a80dc5fSbsh && --timo)
13535a80dc5fSbsh #ifdef DIAGNOSTIC
13545a80dc5fSbsh reg =
13555a80dc5fSbsh #else
13565a80dc5fSbsh (void)
13575a80dc5fSbsh #endif
13585a80dc5fSbsh bus_space_read_4(iot, ioh, IMX_URXD);
13595a80dc5fSbsh #ifdef DIAGNOSTIC
13605a80dc5fSbsh if (!timo)
13615a80dc5fSbsh aprint_error_dev(sc->sc_dev, "imxuart_iflush timeout %02x\n", reg);
13625a80dc5fSbsh #endif
13635a80dc5fSbsh }
13645a80dc5fSbsh
13655a80dc5fSbsh int
imxuhwiflow(struct tty * tp,int block)13665a80dc5fSbsh imxuhwiflow(struct tty *tp, int block)
13675a80dc5fSbsh {
13685a80dc5fSbsh struct imxuart_softc *sc =
13695a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(tp->t_dev));
13705a80dc5fSbsh
13715a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
13725a80dc5fSbsh return (0);
13735a80dc5fSbsh
13745a80dc5fSbsh #ifdef notyet
13755a80dc5fSbsh if (sc->sc_mcr_rts == 0)
13765a80dc5fSbsh return (0);
13775a80dc5fSbsh #endif
13785a80dc5fSbsh
13795a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
13805a80dc5fSbsh
13815a80dc5fSbsh if (block) {
13825a80dc5fSbsh if (!ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_BLOCKED)) {
13835a80dc5fSbsh SET(sc->sc_rx_flags, IMXUART_RX_TTY_BLOCKED);
13845a80dc5fSbsh imxuart_hwiflow(sc);
13855a80dc5fSbsh }
13865a80dc5fSbsh } else {
13875a80dc5fSbsh if (ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED)) {
13885a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED);
13895a80dc5fSbsh imxuart_schedrx(sc);
13905a80dc5fSbsh }
13915a80dc5fSbsh if (ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_BLOCKED)) {
13925a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_TTY_BLOCKED);
13935a80dc5fSbsh imxuart_hwiflow(sc);
13945a80dc5fSbsh }
13955a80dc5fSbsh }
13965a80dc5fSbsh
13975a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
13985a80dc5fSbsh return (1);
13995a80dc5fSbsh }
14005a80dc5fSbsh
14015a80dc5fSbsh /*
14025a80dc5fSbsh * (un)block input via hw flowcontrol
14035a80dc5fSbsh */
14045a80dc5fSbsh void
imxuart_hwiflow(struct imxuart_softc * sc)14055a80dc5fSbsh imxuart_hwiflow(struct imxuart_softc *sc)
14065a80dc5fSbsh {
14075a80dc5fSbsh #ifdef notyet
14085a80dc5fSbsh struct imxuart_regs *regsp= &sc->sc_regs;
14095a80dc5fSbsh
14105a80dc5fSbsh if (sc->sc_mcr_rts == 0)
14115a80dc5fSbsh return;
14125a80dc5fSbsh
14135a80dc5fSbsh if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
14145a80dc5fSbsh CLR(sc->sc_mcr, sc->sc_mcr_rts);
14155a80dc5fSbsh CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
14165a80dc5fSbsh } else {
14175a80dc5fSbsh SET(sc->sc_mcr, sc->sc_mcr_rts);
14185a80dc5fSbsh SET(sc->sc_mcr_active, sc->sc_mcr_rts);
14195a80dc5fSbsh }
14205a80dc5fSbsh UR_WRITE_1(regsp, IMXUART_REG_MCR, sc->sc_mcr_active);
14215a80dc5fSbsh #endif
14225a80dc5fSbsh }
14235a80dc5fSbsh
14245a80dc5fSbsh
14255a80dc5fSbsh void
imxustart(struct tty * tp)14265a80dc5fSbsh imxustart(struct tty *tp)
14275a80dc5fSbsh {
14285a80dc5fSbsh struct imxuart_softc *sc =
14295a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(tp->t_dev));
14305a80dc5fSbsh int s;
14315a80dc5fSbsh u_char *tba;
14325a80dc5fSbsh int tbc;
14335a80dc5fSbsh u_int n;
14345a80dc5fSbsh u_int space;
14355a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
14365a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
14375a80dc5fSbsh
14385a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
14395a80dc5fSbsh return;
14405a80dc5fSbsh
14415a80dc5fSbsh s = spltty();
14425a80dc5fSbsh if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
14435a80dc5fSbsh goto out;
14445a80dc5fSbsh if (sc->sc_tx_stopped)
14455a80dc5fSbsh goto out;
14465a80dc5fSbsh if (!ttypull(tp))
14475a80dc5fSbsh goto out;
14485a80dc5fSbsh
14495a80dc5fSbsh /* Grab the first contiguous region of buffer space. */
14505a80dc5fSbsh tba = tp->t_outq.c_cf;
14515a80dc5fSbsh tbc = ndqb(&tp->t_outq, 0);
14525a80dc5fSbsh
14535a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
14545a80dc5fSbsh
14555a80dc5fSbsh sc->sc_tba = tba;
14565a80dc5fSbsh sc->sc_tbc = tbc;
14575a80dc5fSbsh
14585a80dc5fSbsh SET(tp->t_state, TS_BUSY);
14595a80dc5fSbsh sc->sc_tx_busy = 1;
14605a80dc5fSbsh
14615a80dc5fSbsh space = imxuart_txfifo_space(sc);
14625a80dc5fSbsh n = MIN(sc->sc_tbc, space);
14635a80dc5fSbsh
146491882526Sjmcneill if (n > 0) {
14655a80dc5fSbsh bus_space_write_multi_1(iot, ioh, IMX_UTXD, sc->sc_tba, n);
14665a80dc5fSbsh sc->sc_tbc -= n;
14675a80dc5fSbsh sc->sc_tba += n;
146891882526Sjmcneill }
14695a80dc5fSbsh
14705a80dc5fSbsh /* Enable transmit completion interrupts */
14715a80dc5fSbsh imxuart_control_txint(sc, true);
14725a80dc5fSbsh
14735a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
14745a80dc5fSbsh out:
14755a80dc5fSbsh splx(s);
14765a80dc5fSbsh return;
14775a80dc5fSbsh }
14785a80dc5fSbsh
14795a80dc5fSbsh /*
14805a80dc5fSbsh * Stop output on a line.
14815a80dc5fSbsh */
14825a80dc5fSbsh void
imxustop(struct tty * tp,int flag)14835a80dc5fSbsh imxustop(struct tty *tp, int flag)
14845a80dc5fSbsh {
14855a80dc5fSbsh struct imxuart_softc *sc =
14865a80dc5fSbsh device_lookup_private(&imxuart_cd, IMXUART_UNIT(tp->t_dev));
14875a80dc5fSbsh
14885a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
14895a80dc5fSbsh if (ISSET(tp->t_state, TS_BUSY)) {
14905a80dc5fSbsh /* Stop transmitting at the next chunk. */
14915a80dc5fSbsh sc->sc_tbc = 0;
14925a80dc5fSbsh sc->sc_heldtbc = 0;
14935a80dc5fSbsh if (!ISSET(tp->t_state, TS_TTSTOP))
14945a80dc5fSbsh SET(tp->t_state, TS_FLUSH);
14955a80dc5fSbsh }
14965a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
14975a80dc5fSbsh }
14985a80dc5fSbsh
14995a80dc5fSbsh void
imxudiag(void * arg)15005a80dc5fSbsh imxudiag(void *arg)
15015a80dc5fSbsh {
15025a80dc5fSbsh #ifdef notyet
15035a80dc5fSbsh struct imxuart_softc *sc = arg;
15045a80dc5fSbsh int overflows, floods;
15055a80dc5fSbsh
15065a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
15075a80dc5fSbsh overflows = sc->sc_overflows;
15085a80dc5fSbsh sc->sc_overflows = 0;
15095a80dc5fSbsh floods = sc->sc_floods;
15105a80dc5fSbsh sc->sc_floods = 0;
15115a80dc5fSbsh sc->sc_errors = 0;
15125a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
15135a80dc5fSbsh
15145a80dc5fSbsh log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
15155a80dc5fSbsh device_xname(sc->sc_dev),
15165a80dc5fSbsh overflows, overflows == 1 ? "" : "s",
15175a80dc5fSbsh floods, floods == 1 ? "" : "s");
15185a80dc5fSbsh #endif
15195a80dc5fSbsh }
15205a80dc5fSbsh
15215a80dc5fSbsh integrate void
imxuart_rxsoft(struct imxuart_softc * sc,struct tty * tp)15225a80dc5fSbsh imxuart_rxsoft(struct imxuart_softc *sc, struct tty *tp)
15235a80dc5fSbsh {
15245a80dc5fSbsh int (*rint)(int, struct tty *) = tp->t_linesw->l_rint;
15255a80dc5fSbsh u_int cc, scc, outp;
15265a80dc5fSbsh uint16_t data;
15275a80dc5fSbsh u_int code;
15285a80dc5fSbsh
15295a80dc5fSbsh scc = cc = IMXUART_RBUF_AVAIL(sc);
15305a80dc5fSbsh
15315a80dc5fSbsh #if 0
15325a80dc5fSbsh if (cc == imxuart_rbuf_size-1) {
15335a80dc5fSbsh sc->sc_floods++;
15345a80dc5fSbsh if (sc->sc_errors++ == 0)
15355a80dc5fSbsh callout_reset(&sc->sc_diag_callout, 60 * hz,
15365a80dc5fSbsh imxudiag, sc);
15375a80dc5fSbsh }
15385a80dc5fSbsh #endif
15395a80dc5fSbsh
15405a80dc5fSbsh /* If not yet open, drop the entire buffer content here */
15415a80dc5fSbsh if (!ISSET(tp->t_state, TS_ISOPEN)) {
15425a80dc5fSbsh sc->sc_rbuf_out = sc->sc_rbuf_in;
15435a80dc5fSbsh cc = 0;
15445a80dc5fSbsh }
15455a80dc5fSbsh
15465a80dc5fSbsh outp = sc->sc_rbuf_out;
15475a80dc5fSbsh
15485a80dc5fSbsh #define ERRBITS (IMX_URXD_PRERR|IMX_URXD_BRK|IMX_URXD_FRMERR|IMX_URXD_OVRRUN)
15495a80dc5fSbsh
15505a80dc5fSbsh while (cc) {
15515a80dc5fSbsh data = sc->sc_rbuf[outp];
15525a80dc5fSbsh code = data & IMX_URXD_RX_DATA;
15535a80dc5fSbsh if (ISSET(data, ERRBITS)) {
15545a80dc5fSbsh if (sc->sc_errors.err == 0)
15555a80dc5fSbsh callout_reset(&sc->sc_diag_callout,
15565a80dc5fSbsh 60 * hz, imxudiag, sc);
15575a80dc5fSbsh if (ISSET(data, IMX_URXD_OVRRUN))
15585a80dc5fSbsh sc->sc_errors.ovrrun++;
15595a80dc5fSbsh if (ISSET(data, IMX_URXD_BRK)) {
15605a80dc5fSbsh sc->sc_errors.brk++;
15615a80dc5fSbsh SET(code, TTY_FE);
15625a80dc5fSbsh }
15635a80dc5fSbsh if (ISSET(data, IMX_URXD_FRMERR)) {
15645a80dc5fSbsh sc->sc_errors.frmerr++;
15655a80dc5fSbsh SET(code, TTY_FE);
15665a80dc5fSbsh }
15675a80dc5fSbsh if (ISSET(data, IMX_URXD_PRERR)) {
15685a80dc5fSbsh sc->sc_errors.prerr++;
15695a80dc5fSbsh SET(code, TTY_PE);
15705a80dc5fSbsh }
15715a80dc5fSbsh }
15725a80dc5fSbsh if ((*rint)(code, tp) == -1) {
15735a80dc5fSbsh /*
15745a80dc5fSbsh * The line discipline's buffer is out of space.
15755a80dc5fSbsh */
15765a80dc5fSbsh if (!ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_BLOCKED)) {
15775a80dc5fSbsh /*
15785a80dc5fSbsh * We're either not using flow control, or the
15795a80dc5fSbsh * line discipline didn't tell us to block for
15805a80dc5fSbsh * some reason. Either way, we have no way to
15815a80dc5fSbsh * know when there's more space available, so
15825a80dc5fSbsh * just drop the rest of the data.
15835a80dc5fSbsh */
15845a80dc5fSbsh sc->sc_rbuf_out = sc->sc_rbuf_in;
15855a80dc5fSbsh cc = 0;
15865a80dc5fSbsh } else {
15875a80dc5fSbsh /*
15885a80dc5fSbsh * Don't schedule any more receive processing
15895a80dc5fSbsh * until the line discipline tells us there's
15905a80dc5fSbsh * space available (through imxuhwiflow()).
15915a80dc5fSbsh * Leave the rest of the data in the input
15925a80dc5fSbsh * buffer.
15935a80dc5fSbsh */
15945a80dc5fSbsh SET(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED);
15955a80dc5fSbsh }
15965a80dc5fSbsh break;
15975a80dc5fSbsh }
15985a80dc5fSbsh outp = IMXUART_RBUF_INC(sc, outp, 1);
15995a80dc5fSbsh cc--;
16005a80dc5fSbsh }
16015a80dc5fSbsh
16025a80dc5fSbsh if (cc != scc) {
16035a80dc5fSbsh sc->sc_rbuf_out = outp;
16045a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
16055a80dc5fSbsh
16065a80dc5fSbsh cc = IMXUART_RBUF_SPACE(sc);
16075a80dc5fSbsh
16085a80dc5fSbsh /* Buffers should be ok again, release possible block. */
16095a80dc5fSbsh if (cc >= sc->sc_r_lowat) {
16105a80dc5fSbsh if (ISSET(sc->sc_rx_flags, IMXUART_RX_IBUF_OVERFLOWED)) {
16115a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_IBUF_OVERFLOWED);
16125a80dc5fSbsh imxuart_control_rxint(sc, true);
16135a80dc5fSbsh }
16145a80dc5fSbsh if (ISSET(sc->sc_rx_flags, IMXUART_RX_IBUF_BLOCKED)) {
16155a80dc5fSbsh CLR(sc->sc_rx_flags, IMXUART_RX_IBUF_BLOCKED);
16165a80dc5fSbsh imxuart_hwiflow(sc);
16175a80dc5fSbsh }
16185a80dc5fSbsh }
16195a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
16205a80dc5fSbsh }
16215a80dc5fSbsh }
16225a80dc5fSbsh
16235a80dc5fSbsh integrate void
imxuart_txsoft(struct imxuart_softc * sc,struct tty * tp)16245a80dc5fSbsh imxuart_txsoft(struct imxuart_softc *sc, struct tty *tp)
16255a80dc5fSbsh {
16265a80dc5fSbsh
16275a80dc5fSbsh CLR(tp->t_state, TS_BUSY);
16285a80dc5fSbsh if (ISSET(tp->t_state, TS_FLUSH))
16295a80dc5fSbsh CLR(tp->t_state, TS_FLUSH);
16305a80dc5fSbsh else
16315a80dc5fSbsh ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
16325a80dc5fSbsh (*tp->t_linesw->l_start)(tp);
16335a80dc5fSbsh }
16345a80dc5fSbsh
16355a80dc5fSbsh integrate void
imxuart_stsoft(struct imxuart_softc * sc,struct tty * tp)16365a80dc5fSbsh imxuart_stsoft(struct imxuart_softc *sc, struct tty *tp)
16375a80dc5fSbsh {
16385a80dc5fSbsh #ifdef notyet
16395a80dc5fSbsh u_char msr, delta;
16405a80dc5fSbsh
16415a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
16425a80dc5fSbsh msr = sc->sc_msr;
16435a80dc5fSbsh delta = sc->sc_msr_delta;
16445a80dc5fSbsh sc->sc_msr_delta = 0;
16455a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
16465a80dc5fSbsh
16475a80dc5fSbsh if (ISSET(delta, sc->sc_msr_dcd)) {
16485a80dc5fSbsh /*
16495a80dc5fSbsh * Inform the tty layer that carrier detect changed.
16505a80dc5fSbsh */
16515a80dc5fSbsh (void) (*tp->t_linesw->l_modem)(tp, ISSET(msr, MSR_DCD));
16525a80dc5fSbsh }
16535a80dc5fSbsh
16545a80dc5fSbsh if (ISSET(delta, sc->sc_msr_cts)) {
16555a80dc5fSbsh /* Block or unblock output according to flow control. */
16565a80dc5fSbsh if (ISSET(msr, sc->sc_msr_cts)) {
16575a80dc5fSbsh sc->sc_tx_stopped = 0;
16585a80dc5fSbsh (*tp->t_linesw->l_start)(tp);
16595a80dc5fSbsh } else {
16605a80dc5fSbsh sc->sc_tx_stopped = 1;
16615a80dc5fSbsh }
16625a80dc5fSbsh }
16635a80dc5fSbsh
16645a80dc5fSbsh #endif
16655a80dc5fSbsh #ifdef IMXUART_DEBUG
16665a80dc5fSbsh if (imxuart_debug)
16675a80dc5fSbsh imxustatus(sc, "imxuart_stsoft");
16685a80dc5fSbsh #endif
16695a80dc5fSbsh }
16705a80dc5fSbsh
16715a80dc5fSbsh void
imxusoft(void * arg)16725a80dc5fSbsh imxusoft(void *arg)
16735a80dc5fSbsh {
16745a80dc5fSbsh struct imxuart_softc *sc = arg;
16755a80dc5fSbsh struct tty *tp;
16765a80dc5fSbsh
16775a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
16785a80dc5fSbsh return;
16795a80dc5fSbsh
16805a80dc5fSbsh tp = sc->sc_tty;
16815a80dc5fSbsh
16825a80dc5fSbsh if (sc->sc_rx_ready) {
16835a80dc5fSbsh sc->sc_rx_ready = 0;
16845a80dc5fSbsh imxuart_rxsoft(sc, tp);
16855a80dc5fSbsh }
16865a80dc5fSbsh
16875a80dc5fSbsh if (sc->sc_st_check) {
16885a80dc5fSbsh sc->sc_st_check = 0;
16895a80dc5fSbsh imxuart_stsoft(sc, tp);
16905a80dc5fSbsh }
16915a80dc5fSbsh
16925a80dc5fSbsh if (sc->sc_tx_done) {
16935a80dc5fSbsh sc->sc_tx_done = 0;
16945a80dc5fSbsh imxuart_txsoft(sc, tp);
16955a80dc5fSbsh }
16965a80dc5fSbsh }
16975a80dc5fSbsh
16985a80dc5fSbsh int
imxuintr(void * arg)16995a80dc5fSbsh imxuintr(void *arg)
17005a80dc5fSbsh {
17015a80dc5fSbsh struct imxuart_softc *sc = arg;
17025a80dc5fSbsh uint32_t usr1, usr2;
17035a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
17045a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
17055a80dc5fSbsh
17065a80dc5fSbsh
17075a80dc5fSbsh if (IMXUART_ISALIVE(sc) == 0)
17085a80dc5fSbsh return (0);
17095a80dc5fSbsh
17105a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
17115a80dc5fSbsh
17125a80dc5fSbsh usr2 = bus_space_read_4(iot, ioh, IMX_USR2);
17135a80dc5fSbsh
17145a80dc5fSbsh
17155a80dc5fSbsh do {
17165a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_USR2,
17175a80dc5fSbsh usr2 & (IMX_USR2_BRCD|IMX_USR2_ORE));
17185a80dc5fSbsh if (usr2 & IMX_USR2_BRCD) {
17195a80dc5fSbsh /* Break signal detected */
17205a80dc5fSbsh int cn_trapped = 0;
17215a80dc5fSbsh
17225a80dc5fSbsh cn_check_magic(sc->sc_tty->t_dev,
17235a80dc5fSbsh CNC_BREAK, imxuart_cnm_state);
17245a80dc5fSbsh if (cn_trapped)
1725222bc718Smlelstv goto next;
17265a80dc5fSbsh #if defined(KGDB) && !defined(DDB)
17275a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_KGDB)) {
17285a80dc5fSbsh kgdb_connect(1);
1729222bc718Smlelstv goto next;
17305a80dc5fSbsh }
17315a80dc5fSbsh #endif
17325a80dc5fSbsh }
17335a80dc5fSbsh
17345a80dc5fSbsh if (usr2 & IMX_USR2_RDR)
17355a80dc5fSbsh imxuintr_read(sc);
17365a80dc5fSbsh
17375a80dc5fSbsh #ifdef IMXUART_PPS
17385a80dc5fSbsh {
17395a80dc5fSbsh u_char msr, delta;
17405a80dc5fSbsh
17415a80dc5fSbsh msr = CSR_READ_1(regsp, IMXUART_REG_MSR);
17425a80dc5fSbsh delta = msr ^ sc->sc_msr;
17435a80dc5fSbsh sc->sc_msr = msr;
17445a80dc5fSbsh if ((sc->sc_pps_state.ppsparam.mode & PPS_CAPTUREBOTH) &&
17455a80dc5fSbsh (delta & MSR_DCD)) {
17465a80dc5fSbsh mutex_spin_enter(&timecounter_lock);
17475a80dc5fSbsh pps_capture(&sc->sc_pps_state);
17485a80dc5fSbsh pps_event(&sc->sc_pps_state,
17495a80dc5fSbsh (msr & MSR_DCD) ?
17505a80dc5fSbsh PPS_CAPTUREASSERT :
17515a80dc5fSbsh PPS_CAPTURECLEAR);
17525a80dc5fSbsh mutex_spin_exit(&timecounter_lock);
17535a80dc5fSbsh }
17545a80dc5fSbsh }
17555a80dc5fSbsh #endif
17565a80dc5fSbsh
17575a80dc5fSbsh #ifdef notyet
17585a80dc5fSbsh /*
17595a80dc5fSbsh * Process normal status changes
17605a80dc5fSbsh */
17615a80dc5fSbsh if (ISSET(delta, sc->sc_msr_mask)) {
17625a80dc5fSbsh SET(sc->sc_msr_delta, delta);
17635a80dc5fSbsh
17645a80dc5fSbsh /*
17655a80dc5fSbsh * Stop output immediately if we lose the output
17665a80dc5fSbsh * flow control signal or carrier detect.
17675a80dc5fSbsh */
17685a80dc5fSbsh if (ISSET(~msr, sc->sc_msr_mask)) {
17695a80dc5fSbsh sc->sc_tbc = 0;
17705a80dc5fSbsh sc->sc_heldtbc = 0;
17715a80dc5fSbsh #ifdef IMXUART_DEBUG
17725a80dc5fSbsh if (imxuart_debug)
17735a80dc5fSbsh imxustatus(sc, "imxuintr ");
17745a80dc5fSbsh #endif
17755a80dc5fSbsh }
17765a80dc5fSbsh
17775a80dc5fSbsh sc->sc_st_check = 1;
17785a80dc5fSbsh }
17795a80dc5fSbsh #endif
17805a80dc5fSbsh
1781222bc718Smlelstv next:
17825a80dc5fSbsh usr2 = bus_space_read_4(iot, ioh, IMX_USR2);
17835a80dc5fSbsh } while (usr2 & (IMX_USR2_RDR|IMX_USR2_BRCD));
17845a80dc5fSbsh
17855a80dc5fSbsh usr1 = bus_space_read_4(iot, ioh, IMX_USR1);
17865a80dc5fSbsh if (usr1 & IMX_USR1_TRDY)
17875a80dc5fSbsh imxuintr_send(sc);
17885a80dc5fSbsh
17895a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
17905a80dc5fSbsh
17915a80dc5fSbsh /* Wake up the poller. */
17925a80dc5fSbsh softint_schedule(sc->sc_si);
17935a80dc5fSbsh
17947b0b7dedStls #ifdef RND_COM
17955a80dc5fSbsh rnd_add_uint32(&sc->rnd_source, iir | lsr);
17965a80dc5fSbsh #endif
17975a80dc5fSbsh
17985a80dc5fSbsh return (1);
17995a80dc5fSbsh }
18005a80dc5fSbsh
18015a80dc5fSbsh
18025a80dc5fSbsh /*
18035a80dc5fSbsh * called when there is least one character in rxfifo
18045a80dc5fSbsh *
18055a80dc5fSbsh */
18065a80dc5fSbsh
18075a80dc5fSbsh static void
imxuintr_read(struct imxuart_softc * sc)18085a80dc5fSbsh imxuintr_read(struct imxuart_softc *sc)
18095a80dc5fSbsh {
18105a80dc5fSbsh int cc;
18115a80dc5fSbsh uint16_t rd;
18125a80dc5fSbsh uint32_t usr2;
18135a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
18145a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
18155a80dc5fSbsh
18165a80dc5fSbsh cc = IMXUART_RBUF_SPACE(sc);
18175a80dc5fSbsh
18185a80dc5fSbsh /* clear aging timer interrupt */
18195a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_USR1, IMX_USR1_AGTIM);
18205a80dc5fSbsh
18215a80dc5fSbsh while (cc > 0) {
18225a80dc5fSbsh int cn_trapped = 0;
18235a80dc5fSbsh
18245a80dc5fSbsh sc->sc_rbuf[sc->sc_rbuf_in] = rd =
18255a80dc5fSbsh bus_space_read_4(iot, ioh, IMX_URXD);
18265a80dc5fSbsh
18275a80dc5fSbsh cn_check_magic(sc->sc_tty->t_dev,
18285a80dc5fSbsh rd & 0xff, imxuart_cnm_state);
18295a80dc5fSbsh
18305a80dc5fSbsh if (!cn_trapped) {
1831a4103ccdSryo #if defined(DDB) && defined(DDB_KEYCODE)
1832a4103ccdSryo /*
1833a4103ccdSryo * Temporary hack so that I can force the kernel into
1834a4103ccdSryo * the debugger via the serial port
1835a4103ccdSryo */
1836a4103ccdSryo if ((rd & 0xff) == DDB_KEYCODE)
1837a4103ccdSryo Debugger();
1838a4103ccdSryo #endif
18395a80dc5fSbsh sc->sc_rbuf_in = IMXUART_RBUF_INC(sc, sc->sc_rbuf_in, 1);
18405a80dc5fSbsh cc--;
18415a80dc5fSbsh }
18425a80dc5fSbsh
18435a80dc5fSbsh usr2 = bus_space_read_4(iot, ioh, IMX_USR2);
18445a80dc5fSbsh if (!(usr2 & IMX_USR2_RDR))
18455a80dc5fSbsh break;
18465a80dc5fSbsh }
18475a80dc5fSbsh
18485a80dc5fSbsh /*
18495a80dc5fSbsh * Current string of incoming characters ended because
18505a80dc5fSbsh * no more data was available or we ran out of space.
18515a80dc5fSbsh * Schedule a receive event if any data was received.
18525a80dc5fSbsh * If we're out of space, turn off receive interrupts.
18535a80dc5fSbsh */
18545a80dc5fSbsh if (!ISSET(sc->sc_rx_flags, IMXUART_RX_TTY_OVERFLOWED))
18555a80dc5fSbsh sc->sc_rx_ready = 1;
18565a80dc5fSbsh /*
18575a80dc5fSbsh * See if we are in danger of overflowing a buffer. If
18585a80dc5fSbsh * so, use hardware flow control to ease the pressure.
18595a80dc5fSbsh */
18605a80dc5fSbsh if (!ISSET(sc->sc_rx_flags, IMXUART_RX_IBUF_BLOCKED) &&
18615a80dc5fSbsh cc < sc->sc_r_hiwat) {
18625a80dc5fSbsh sc->sc_rx_flags |= IMXUART_RX_IBUF_BLOCKED;
18635a80dc5fSbsh imxuart_hwiflow(sc);
18645a80dc5fSbsh }
18655a80dc5fSbsh
18665a80dc5fSbsh /*
18675a80dc5fSbsh * If we're out of space, disable receive interrupts
18685a80dc5fSbsh * until the queue has drained a bit.
18695a80dc5fSbsh */
18705a80dc5fSbsh if (!cc) {
18715a80dc5fSbsh sc->sc_rx_flags |= IMXUART_RX_IBUF_OVERFLOWED;
18725a80dc5fSbsh imxuart_control_rxint(sc, false);
18735a80dc5fSbsh }
18745a80dc5fSbsh }
18755a80dc5fSbsh
18765a80dc5fSbsh
18775a80dc5fSbsh
18785a80dc5fSbsh /*
18795a80dc5fSbsh * find how many chars we can put into tx-fifo
18805a80dc5fSbsh */
18815a80dc5fSbsh static u_int
imxuart_txfifo_space(struct imxuart_softc * sc)18825a80dc5fSbsh imxuart_txfifo_space(struct imxuart_softc *sc)
18835a80dc5fSbsh {
18845a80dc5fSbsh uint32_t usr1, usr2;
18855a80dc5fSbsh u_int cc;
18865a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
18875a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
18885a80dc5fSbsh
18895a80dc5fSbsh usr2 = bus_space_read_4(iot, ioh, IMX_USR2);
18905a80dc5fSbsh if (usr2 & IMX_USR2_TXFE)
18915a80dc5fSbsh cc = sc->sc_txfifo_len;
18925a80dc5fSbsh else {
18935a80dc5fSbsh usr1 = bus_space_read_4(iot, ioh, IMX_USR1);
18945a80dc5fSbsh if (usr1 & IMX_USR1_TRDY)
18955a80dc5fSbsh cc = sc->sc_txfifo_thresh;
18965a80dc5fSbsh else
18975a80dc5fSbsh cc = 0;
18985a80dc5fSbsh }
18995a80dc5fSbsh
19005a80dc5fSbsh return cc;
19015a80dc5fSbsh }
19025a80dc5fSbsh
19035a80dc5fSbsh void
imxuintr_send(struct imxuart_softc * sc)19045a80dc5fSbsh imxuintr_send(struct imxuart_softc *sc)
19055a80dc5fSbsh {
19065a80dc5fSbsh uint32_t usr2;
19075a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
19085a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
19095a80dc5fSbsh int cc = 0;
19105a80dc5fSbsh
19115a80dc5fSbsh usr2 = bus_space_read_4(iot, ioh, IMX_USR2);
19125a80dc5fSbsh
19135a80dc5fSbsh if (sc->sc_pending) {
19145a80dc5fSbsh if (usr2 & IMX_USR2_TXFE) {
19155a80dc5fSbsh imxuart_load_pendings(sc);
19165a80dc5fSbsh sc->sc_tbc = sc->sc_heldtbc;
19175a80dc5fSbsh sc->sc_heldtbc = 0;
19185a80dc5fSbsh }
19195a80dc5fSbsh else {
19205a80dc5fSbsh /* wait for TX fifo empty */
19215a80dc5fSbsh imxuart_control_txint(sc, true);
19225a80dc5fSbsh return;
19235a80dc5fSbsh }
19245a80dc5fSbsh }
19255a80dc5fSbsh
19265a80dc5fSbsh cc = imxuart_txfifo_space(sc);
19275a80dc5fSbsh cc = MIN(cc, sc->sc_tbc);
19285a80dc5fSbsh
19295a80dc5fSbsh if (cc > 0) {
19305a80dc5fSbsh bus_space_write_multi_1(iot, ioh, IMX_UTXD, sc->sc_tba, cc);
19315a80dc5fSbsh sc->sc_tbc -= cc;
19325a80dc5fSbsh sc->sc_tba += cc;
19335a80dc5fSbsh }
19345a80dc5fSbsh
19355a80dc5fSbsh if (sc->sc_tbc > 0)
19365a80dc5fSbsh imxuart_control_txint(sc, true);
19375a80dc5fSbsh else {
19385a80dc5fSbsh /* no more chars to send.
19395a80dc5fSbsh we don't need tx interrupt any more. */
19405a80dc5fSbsh imxuart_control_txint(sc, false);
19415a80dc5fSbsh if (sc->sc_tx_busy) {
19425a80dc5fSbsh sc->sc_tx_busy = 0;
19435a80dc5fSbsh sc->sc_tx_done = 1;
19445a80dc5fSbsh }
19455a80dc5fSbsh }
19465a80dc5fSbsh }
19475a80dc5fSbsh
19485a80dc5fSbsh static void
imxuart_disable_all_interrupts(struct imxuart_softc * sc)19495a80dc5fSbsh imxuart_disable_all_interrupts(struct imxuart_softc *sc)
19505a80dc5fSbsh {
19515a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
19525a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
19535a80dc5fSbsh
19545a80dc5fSbsh sc->sc_ucr1 &= ~IMXUART_INTRS_UCR1;
19555a80dc5fSbsh sc->sc_ucr2 &= ~IMXUART_INTRS_UCR2;
19565a80dc5fSbsh sc->sc_ucr3 &= ~IMXUART_INTRS_UCR3;
19575a80dc5fSbsh sc->sc_ucr4 &= ~IMXUART_INTRS_UCR4;
19585a80dc5fSbsh
19595a80dc5fSbsh
19605a80dc5fSbsh bus_space_write_region_4(iot, ioh, IMX_UCR1, sc->sc_ucr, 4);
19615a80dc5fSbsh }
19625a80dc5fSbsh
19635a80dc5fSbsh static void
imxuart_control_rxint(struct imxuart_softc * sc,bool enable)19645a80dc5fSbsh imxuart_control_rxint(struct imxuart_softc *sc, bool enable)
19655a80dc5fSbsh {
19665a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
19675a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
19685a80dc5fSbsh uint32_t ucr1, ucr2;
19695a80dc5fSbsh
19705a80dc5fSbsh ucr1 = sc->sc_ucr1;
19715a80dc5fSbsh ucr2 = sc->sc_ucr2;
19725a80dc5fSbsh
19735a80dc5fSbsh if (enable) {
19745a80dc5fSbsh ucr1 |= IMX_UCR1_RRDYEN;
19755a80dc5fSbsh ucr2 |= IMX_UCR2_ATEN;
19765a80dc5fSbsh }
19775a80dc5fSbsh else {
19785a80dc5fSbsh ucr1 &= ~IMX_UCR1_RRDYEN;
19795a80dc5fSbsh ucr2 &= ~IMX_UCR2_ATEN;
19805a80dc5fSbsh }
19815a80dc5fSbsh
19825a80dc5fSbsh if (ucr1 != sc->sc_ucr1 || ucr2 != sc->sc_ucr2) {
19835a80dc5fSbsh sc->sc_ucr1 = ucr1;
19845a80dc5fSbsh sc->sc_ucr2 = ucr2;
19855a80dc5fSbsh bus_space_write_region_4(iot, ioh, IMX_UCR1, sc->sc_ucr, 2);
19865a80dc5fSbsh }
19875a80dc5fSbsh }
19885a80dc5fSbsh
19895a80dc5fSbsh static void
imxuart_control_txint(struct imxuart_softc * sc,bool enable)19905a80dc5fSbsh imxuart_control_txint(struct imxuart_softc *sc, bool enable)
19915a80dc5fSbsh {
19925a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
19935a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
19945a80dc5fSbsh uint32_t ucr1;
19955a80dc5fSbsh uint32_t mask;
19965a80dc5fSbsh
19975a80dc5fSbsh /* if parameter change is pending, get interrupt when Tx fifo
19985a80dc5fSbsh is completely empty. otherwise, get interrupt when txfifo
19995a80dc5fSbsh has less characters than threshold */
20005a80dc5fSbsh mask = sc->sc_pending ? IMX_UCR1_TXMPTYEN : IMX_UCR1_TRDYEN;
20015a80dc5fSbsh
20025a80dc5fSbsh ucr1 = sc->sc_ucr1;
20035a80dc5fSbsh
20045a80dc5fSbsh CLR(ucr1, IMX_UCR1_TXMPTYEN|IMX_UCR1_TRDYEN);
20055a80dc5fSbsh if (enable)
20065a80dc5fSbsh SET(ucr1, mask);
20075a80dc5fSbsh
20085a80dc5fSbsh if (ucr1 != sc->sc_ucr1) {
20095a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR1, ucr1);
20105a80dc5fSbsh sc->sc_ucr1 = ucr1;
20115a80dc5fSbsh }
20125a80dc5fSbsh }
20135a80dc5fSbsh
20145a80dc5fSbsh
20155a80dc5fSbsh static void
imxuart_load_params(struct imxuart_softc * sc)20165a80dc5fSbsh imxuart_load_params(struct imxuart_softc *sc)
20175a80dc5fSbsh {
20185a80dc5fSbsh uint32_t ucr2;
20195a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
20205a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
20215a80dc5fSbsh
20225a80dc5fSbsh ucr2 = (sc->sc_ucr2_d & ~IMX_UCR2_ATEN) |
20235a80dc5fSbsh (sc->sc_ucr2 & IMX_UCR2_ATEN);
20245a80dc5fSbsh
20255a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR2, ucr2);
20265a80dc5fSbsh sc->sc_ucr2 = ucr2;
20275a80dc5fSbsh }
20285a80dc5fSbsh
20295a80dc5fSbsh static void
imxuart_load_speed(struct imxuart_softc * sc)20305a80dc5fSbsh imxuart_load_speed(struct imxuart_softc *sc)
20315a80dc5fSbsh {
20325a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
20335a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
20345a80dc5fSbsh int n, rfdiv, ufcr;
20355a80dc5fSbsh
20365a80dc5fSbsh #ifdef notyet
20375a80dc5fSbsh /*
20385a80dc5fSbsh * Set the FIFO threshold based on the receive speed.
20395a80dc5fSbsh *
20405a80dc5fSbsh * * If it's a low speed, it's probably a mouse or some other
20415a80dc5fSbsh * interactive device, so set the threshold low.
20425a80dc5fSbsh * * If it's a high speed, trim the trigger level down to prevent
20435a80dc5fSbsh * overflows.
20445a80dc5fSbsh * * Otherwise set it a bit higher.
20455a80dc5fSbsh */
20465a80dc5fSbsh if (t->c_ospeed <= 1200)
20475a80dc5fSbsh sc->sc_fifo = FIFO_ENABLE | FIFO_TRIGGER_1;
20485a80dc5fSbsh else if (t->c_ospeed <= 38400)
20495a80dc5fSbsh sc->sc_fifo = FIFO_ENABLE | FIFO_TRIGGER_8;
20505a80dc5fSbsh else
20515a80dc5fSbsh sc->sc_fifo = FIFO_ENABLE | FIFO_TRIGGER_4;
20525a80dc5fSbsh #endif
20535a80dc5fSbsh
20545a80dc5fSbsh n = 32 - sc->sc_txfifo_thresh;
20555a80dc5fSbsh n = MAX(2, n);
20565a80dc5fSbsh
20575a80dc5fSbsh rfdiv = IMX_UFCR_DIVIDER_TO_RFDIV(imxuart_freqdiv);
20585a80dc5fSbsh
20595a80dc5fSbsh ufcr = (n << IMX_UFCR_TXTL_SHIFT) |
20605a80dc5fSbsh (rfdiv << IMX_UFCR_RFDIV_SHIFT) |
20615a80dc5fSbsh (16 << IMX_UFCR_RXTL_SHIFT);
20625a80dc5fSbsh
20635a80dc5fSbsh /* keep DCE/DTE bit */
20645a80dc5fSbsh ufcr |= bus_space_read_4(iot, ioh, IMX_UFCR) & IMX_UFCR_DCEDTE;
20655a80dc5fSbsh
20665a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UFCR, ufcr);
20675a80dc5fSbsh
20685a80dc5fSbsh /* UBIR must updated before UBMR */
20695a80dc5fSbsh bus_space_write_4(iot, ioh,
20705a80dc5fSbsh IMX_UBIR, sc->sc_ratio.numerator);
20715a80dc5fSbsh bus_space_write_4(iot, ioh,
20725a80dc5fSbsh IMX_UBMR, sc->sc_ratio.modulator);
20735a80dc5fSbsh
20745a80dc5fSbsh
20755a80dc5fSbsh }
20765a80dc5fSbsh
20775a80dc5fSbsh
20785a80dc5fSbsh static void
imxuart_load_pendings(struct imxuart_softc * sc)20795a80dc5fSbsh imxuart_load_pendings(struct imxuart_softc *sc)
20805a80dc5fSbsh {
20815a80dc5fSbsh if (sc->sc_pending & IMXUART_PEND_PARAM)
20825a80dc5fSbsh imxuart_load_params(sc);
20835a80dc5fSbsh if (sc->sc_pending & IMXUART_PEND_SPEED)
20845a80dc5fSbsh imxuart_load_speed(sc);
20855a80dc5fSbsh sc->sc_pending = 0;
20865a80dc5fSbsh }
20875a80dc5fSbsh
20885a80dc5fSbsh /*
20895a80dc5fSbsh * The following functions are polled getc and putc routines, shared
20905a80dc5fSbsh * by the console and kgdb glue.
20915a80dc5fSbsh *
20925a80dc5fSbsh * The read-ahead code is so that you can detect pending in-band
20935a80dc5fSbsh * cn_magic in polled mode while doing output rather than having to
20945a80dc5fSbsh * wait until the kernel decides it needs input.
20955a80dc5fSbsh */
20965a80dc5fSbsh
20975a80dc5fSbsh #define READAHEAD_RING_LEN 16
20985a80dc5fSbsh static int imxuart_readahead[READAHEAD_RING_LEN];
20995a80dc5fSbsh static int imxuart_readahead_in = 0;
21005a80dc5fSbsh static int imxuart_readahead_out = 0;
21015a80dc5fSbsh #define READAHEAD_IS_EMPTY() (imxuart_readahead_in==imxuart_readahead_out)
21025a80dc5fSbsh #define READAHEAD_IS_FULL() \
21035a80dc5fSbsh (((imxuart_readahead_in+1) & (READAHEAD_RING_LEN-1)) ==imxuart_readahead_out)
21045a80dc5fSbsh
21055a80dc5fSbsh int
imxuart_common_getc(dev_t dev,struct imxuart_regs * regsp)21065a80dc5fSbsh imxuart_common_getc(dev_t dev, struct imxuart_regs *regsp)
21075a80dc5fSbsh {
21085a80dc5fSbsh int s = splserial();
21095a80dc5fSbsh u_char c;
21105a80dc5fSbsh bus_space_tag_t iot = regsp->ur_iot;
21115a80dc5fSbsh bus_space_handle_t ioh = regsp->ur_ioh;
21125a80dc5fSbsh uint32_t usr2;
21135a80dc5fSbsh
21145a80dc5fSbsh /* got a character from reading things earlier */
21155396213aSskrll if (!READAHEAD_IS_EMPTY()) {
21165a80dc5fSbsh c = imxuart_readahead[imxuart_readahead_out];
21175a80dc5fSbsh imxuart_readahead_out = (imxuart_readahead_out + 1) &
21185a80dc5fSbsh (READAHEAD_RING_LEN-1);
21195a80dc5fSbsh splx(s);
21205a80dc5fSbsh return (c);
21215a80dc5fSbsh }
21225a80dc5fSbsh
21235a80dc5fSbsh /* block until a character becomes available */
21245a80dc5fSbsh while (!((usr2 = bus_space_read_4(iot, ioh, IMX_USR2)) & IMX_USR2_RDR))
2125*dbfa10e5Sriastradh continue;
21265a80dc5fSbsh
21275a80dc5fSbsh c = 0xff & bus_space_read_4(iot, ioh, IMX_URXD);
21285a80dc5fSbsh
21295a80dc5fSbsh {
2130*dbfa10e5Sriastradh int cn_trapped __unused = 0;
21315a80dc5fSbsh if (!db_active)
21325a80dc5fSbsh cn_check_magic(dev, c, imxuart_cnm_state);
21335a80dc5fSbsh }
21345a80dc5fSbsh splx(s);
21355a80dc5fSbsh return (c);
21365a80dc5fSbsh }
21375a80dc5fSbsh
21385a80dc5fSbsh void
imxuart_common_putc(dev_t dev,struct imxuart_regs * regsp,int c)21395a80dc5fSbsh imxuart_common_putc(dev_t dev, struct imxuart_regs *regsp, int c)
21405a80dc5fSbsh {
21415a80dc5fSbsh int s = splserial();
21425a80dc5fSbsh int cin, timo;
21435a80dc5fSbsh bus_space_tag_t iot = regsp->ur_iot;
21445a80dc5fSbsh bus_space_handle_t ioh = regsp->ur_ioh;
21455a80dc5fSbsh uint32_t usr2;
21465a80dc5fSbsh
21475a80dc5fSbsh if (!READAHEAD_IS_FULL() &&
21485a80dc5fSbsh ((usr2 = bus_space_read_4(iot, ioh, IMX_USR2)) & IMX_USR2_RDR)) {
21495a80dc5fSbsh
21503187e4c6Shkenken int __attribute__((__unused__))cn_trapped = 0;
21515a80dc5fSbsh cin = bus_space_read_4(iot, ioh, IMX_URXD);
21525a80dc5fSbsh cn_check_magic(dev, cin & 0xff, imxuart_cnm_state);
2153e3b04c30Sskrll imxuart_readahead[imxuart_readahead_in] = cin & 0xff;
21545a80dc5fSbsh imxuart_readahead_in = (imxuart_readahead_in + 1) &
21555a80dc5fSbsh (READAHEAD_RING_LEN-1);
21565a80dc5fSbsh }
21575a80dc5fSbsh
21585a80dc5fSbsh /* wait for any pending transmission to finish */
21595a80dc5fSbsh timo = 150000;
21605a80dc5fSbsh do {
21615a80dc5fSbsh if (bus_space_read_4(iot, ioh, IMX_USR1) & IMX_USR1_TRDY) {
21625a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UTXD, c);
21635a80dc5fSbsh break;
21645a80dc5fSbsh }
21655a80dc5fSbsh } while(--timo > 0);
21665a80dc5fSbsh
21675a80dc5fSbsh IMXUART_BARRIER(regsp, BR | BW);
21685a80dc5fSbsh
21695a80dc5fSbsh splx(s);
21705a80dc5fSbsh }
21715a80dc5fSbsh
21725a80dc5fSbsh /*
2173f0a9db03Sryo * Initialize UART
21745a80dc5fSbsh */
21755a80dc5fSbsh int
imxuart_init(struct imxuart_regs * regsp,int rate,tcflag_t cflag,int domap)2176d0174d87Sryo imxuart_init(struct imxuart_regs *regsp, int rate, tcflag_t cflag, int domap)
21775a80dc5fSbsh {
21785a80dc5fSbsh struct imxuart_baudrate_ratio ratio;
21795a80dc5fSbsh int rfdiv = IMX_UFCR_DIVIDER_TO_RFDIV(imxuart_freqdiv);
21805a80dc5fSbsh uint32_t ufcr;
2181d0174d87Sryo int error;
21825a80dc5fSbsh
2183d0174d87Sryo if (domap && (error = bus_space_map(regsp->ur_iot, regsp->ur_iobase,
2184d0174d87Sryo IMX_UART_SIZE, 0, ®sp->ur_ioh)) != 0)
2185d0174d87Sryo return error;
21865a80dc5fSbsh
2187b6ae72fbSjmcneill if (imxuart_freq != 0) {
21885a80dc5fSbsh if (imxuspeed(rate, &ratio) < 0)
21895a80dc5fSbsh return EINVAL;
21905a80dc5fSbsh
21915a80dc5fSbsh /* UBIR must updated before UBMR */
21925a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh,
21935a80dc5fSbsh IMX_UBIR, ratio.numerator);
21945a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh,
21955a80dc5fSbsh IMX_UBMR, ratio.modulator);
2196b6ae72fbSjmcneill }
21975a80dc5fSbsh
21985a80dc5fSbsh /* XXX: DTREN, DPEC */
21995a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_UCR3,
22005a80dc5fSbsh IMX_UCR3_DSR|IMX_UCR3_RXDMUXSEL);
22015a80dc5fSbsh
2202b6ae72fbSjmcneill ufcr = bus_space_read_4(regsp->ur_iot, regsp->ur_ioh, IMX_UFCR);
2203b6ae72fbSjmcneill ufcr &= ~IMX_UFCR_TXTL;
2204b6ae72fbSjmcneill ufcr |= (8 << IMX_UFCR_TXTL_SHIFT);
2205b6ae72fbSjmcneill ufcr &= ~IMX_UFCR_RXTL;
2206b6ae72fbSjmcneill ufcr |= (1 << IMX_UFCR_RXTL_SHIFT);
2207b6ae72fbSjmcneill if (imxuart_freq != 0) {
2208b6ae72fbSjmcneill ufcr &= ~IMX_UFCR_RFDIV;
2209b6ae72fbSjmcneill ufcr |= (rfdiv << IMX_UFCR_RFDIV_SHIFT);
2210b6ae72fbSjmcneill }
22115a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_UFCR, ufcr);
22125a80dc5fSbsh
2213b6ae72fbSjmcneill if (imxuart_freq != 0) {
22145a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_ONEMS,
22155a80dc5fSbsh imxuart_freq / imxuart_freqdiv / 1000);
2216b6ae72fbSjmcneill }
22175a80dc5fSbsh
22185a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_UCR2,
22195a80dc5fSbsh IMX_UCR2_IRTS|
22205a80dc5fSbsh IMX_UCR2_CTSC|
22215a80dc5fSbsh IMX_UCR2_WS|IMX_UCR2_TXEN|
22225a80dc5fSbsh IMX_UCR2_RXEN|IMX_UCR2_SRST);
22235a80dc5fSbsh /* clear status registers */
22245a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_USR1, 0xffff);
22255a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_USR2, 0xffff);
22265a80dc5fSbsh
22275a80dc5fSbsh
22285a80dc5fSbsh bus_space_write_4(regsp->ur_iot, regsp->ur_ioh, IMX_UCR1,
22295a80dc5fSbsh IMX_UCR1_UARTEN);
22305a80dc5fSbsh
22315a80dc5fSbsh return (0);
22325a80dc5fSbsh }
22335a80dc5fSbsh
22345a80dc5fSbsh
22355a80dc5fSbsh /*
22365a80dc5fSbsh * Following are all routines needed for UART to act as console
22375a80dc5fSbsh */
22385a80dc5fSbsh struct consdev imxucons = {
22395a80dc5fSbsh NULL, NULL, imxucngetc, imxucnputc, imxucnpollc, NULL, NULL, NULL,
22405a80dc5fSbsh NODEV, CN_NORMAL
22415a80dc5fSbsh };
22425a80dc5fSbsh
22435a80dc5fSbsh
22445a80dc5fSbsh int
imxuart_cnattach(bus_space_tag_t iot,paddr_t iobase,u_int rate,tcflag_t cflag)22454f4d98d9Shkenken imxuart_cnattach(bus_space_tag_t iot, paddr_t iobase, u_int rate,
22465a80dc5fSbsh tcflag_t cflag)
22475a80dc5fSbsh {
22485a80dc5fSbsh struct imxuart_regs regs;
22495a80dc5fSbsh int res;
22505a80dc5fSbsh
22515a80dc5fSbsh regs.ur_iot = iot;
22525a80dc5fSbsh regs.ur_iobase = iobase;
22535a80dc5fSbsh
2254d0174d87Sryo res = imxuart_init(®s, rate, cflag, true);
22555a80dc5fSbsh if (res)
22565a80dc5fSbsh return (res);
22575a80dc5fSbsh
22585a80dc5fSbsh cn_tab = &imxucons;
22595a80dc5fSbsh cn_init_magic(&imxuart_cnm_state);
22605a80dc5fSbsh cn_set_magic("\047\001"); /* default magic is BREAK */
22615a80dc5fSbsh
22625a80dc5fSbsh imxuconsrate = rate;
22635a80dc5fSbsh imxuconscflag = cflag;
22645a80dc5fSbsh
22655a80dc5fSbsh imxuconsregs = regs;
22665a80dc5fSbsh
2267825088edSmatt return 0;
2268825088edSmatt }
2269825088edSmatt
22705a80dc5fSbsh int
imxucngetc(dev_t dev)22715a80dc5fSbsh imxucngetc(dev_t dev)
22725a80dc5fSbsh {
22735a80dc5fSbsh return (imxuart_common_getc(dev, &imxuconsregs));
22745a80dc5fSbsh }
22755a80dc5fSbsh
22765a80dc5fSbsh /*
22775a80dc5fSbsh * Console kernel output character routine.
22785a80dc5fSbsh */
22795a80dc5fSbsh void
imxucnputc(dev_t dev,int c)22805a80dc5fSbsh imxucnputc(dev_t dev, int c)
22815a80dc5fSbsh {
22825a80dc5fSbsh imxuart_common_putc(dev, &imxuconsregs, c);
22835a80dc5fSbsh }
22845a80dc5fSbsh
22855a80dc5fSbsh void
imxucnpollc(dev_t dev,int on)22865a80dc5fSbsh imxucnpollc(dev_t dev, int on)
22875a80dc5fSbsh {
22885a80dc5fSbsh
2289c2b23d53Smlelstv imxuart_readahead_in = 0;
2290c2b23d53Smlelstv imxuart_readahead_out = 0;
22915a80dc5fSbsh }
22925a80dc5fSbsh
22935a80dc5fSbsh #ifdef KGDB
22945a80dc5fSbsh int
imxuart_kgdb_attach(bus_space_tag_t iot,paddr_t iobase,u_int rate,tcflag_t cflag)22955a80dc5fSbsh imxuart_kgdb_attach(bus_space_tag_t iot, paddr_t iobase, u_int rate,
22965a80dc5fSbsh tcflag_t cflag)
22975a80dc5fSbsh {
22985a80dc5fSbsh int res;
22995a80dc5fSbsh
23005a80dc5fSbsh if (iot == imxuconsregs.ur_iot &&
23015a80dc5fSbsh iobase == imxuconsregs.ur_iobase) {
23025a80dc5fSbsh #if !defined(DDB)
23035a80dc5fSbsh return (EBUSY); /* cannot share with console */
23045a80dc5fSbsh #else
23055a80dc5fSbsh imxu_kgdb_regs.ur_iot = iot;
23065a80dc5fSbsh imxu_kgdb_regs.ur_ioh = imxuconsregs.ur_ioh;
23075a80dc5fSbsh imxu_kgdb_regs.ur_iobase = iobase;
23085a80dc5fSbsh #endif
23095a80dc5fSbsh } else {
23105a80dc5fSbsh imxu_kgdb_regs.ur_iot = iot;
23115a80dc5fSbsh imxu_kgdb_regs.ur_iobase = iobase;
23125a80dc5fSbsh
2313d0174d87Sryo res = imxuart_init(&imxu_kgdb_regs, rate, cflag, true);
23145a80dc5fSbsh if (res)
23155a80dc5fSbsh return (res);
23165a80dc5fSbsh
23175a80dc5fSbsh /*
23185a80dc5fSbsh * XXXfvdl this shouldn't be needed, but the cn_magic goo
23195a80dc5fSbsh * expects this to be initialized
23205a80dc5fSbsh */
23215a80dc5fSbsh cn_init_magic(&imxuart_cnm_state);
23225a80dc5fSbsh cn_set_magic("\047\001");
23235a80dc5fSbsh }
23245a80dc5fSbsh
23255a80dc5fSbsh kgdb_attach(imxuart_kgdb_getc, imxuart_kgdb_putc, &imxu_kgdb_regs);
23265a80dc5fSbsh kgdb_dev = 123; /* unneeded, only to satisfy some tests */
23275a80dc5fSbsh
23285a80dc5fSbsh return (0);
23295a80dc5fSbsh }
23305a80dc5fSbsh
23315a80dc5fSbsh /* ARGSUSED */
23325a80dc5fSbsh int
imxuart_kgdb_getc(void * arg)23335a80dc5fSbsh imxuart_kgdb_getc(void *arg)
23345a80dc5fSbsh {
23355a80dc5fSbsh struct imxuart_regs *regs = arg;
23365a80dc5fSbsh
23375a80dc5fSbsh return (imxuart_common_getc(NODEV, regs));
23385a80dc5fSbsh }
23395a80dc5fSbsh
23405a80dc5fSbsh /* ARGSUSED */
23415a80dc5fSbsh void
imxuart_kgdb_putc(void * arg,int c)23425a80dc5fSbsh imxuart_kgdb_putc(void *arg, int c)
23435a80dc5fSbsh {
23445a80dc5fSbsh struct imxuart_regs *regs = arg;
23455a80dc5fSbsh
23465a80dc5fSbsh imxuart_common_putc(NODEV, regs, c);
23475a80dc5fSbsh }
23485a80dc5fSbsh #endif /* KGDB */
23495a80dc5fSbsh
23505a80dc5fSbsh /* helper function to identify the imxu ports used by
23515a80dc5fSbsh console or KGDB (and not yet autoconf attached) */
23525a80dc5fSbsh int
imxuart_is_console(bus_space_tag_t iot,bus_addr_t iobase,bus_space_handle_t * ioh)23535a80dc5fSbsh imxuart_is_console(bus_space_tag_t iot, bus_addr_t iobase, bus_space_handle_t *ioh)
23545a80dc5fSbsh {
23555a80dc5fSbsh bus_space_handle_t help;
23565a80dc5fSbsh
23575a80dc5fSbsh if (!imxuconsattached &&
23585a80dc5fSbsh iot == imxuconsregs.ur_iot && iobase == imxuconsregs.ur_iobase)
23595a80dc5fSbsh help = imxuconsregs.ur_ioh;
23605a80dc5fSbsh #ifdef KGDB
23615a80dc5fSbsh else if (!imxu_kgdb_attached &&
23625a80dc5fSbsh iot == imxu_kgdb_regs.ur_iot && iobase == imxu_kgdb_regs.ur_iobase)
23635a80dc5fSbsh help = imxu_kgdb_regs.ur_ioh;
23645a80dc5fSbsh #endif
23655a80dc5fSbsh else
23665a80dc5fSbsh return (0);
23675a80dc5fSbsh
23685a80dc5fSbsh if (ioh)
23695a80dc5fSbsh *ioh = help;
23705a80dc5fSbsh return (1);
23715a80dc5fSbsh }
23725a80dc5fSbsh
23735a80dc5fSbsh #ifdef notyet
23745a80dc5fSbsh
23755a80dc5fSbsh bool
imxuart_cleanup(device_t self,int how)23765a80dc5fSbsh imxuart_cleanup(device_t self, int how)
23775a80dc5fSbsh {
23785a80dc5fSbsh /*
23795a80dc5fSbsh * this routine exists to serve as a shutdown hook for systems that
23805a80dc5fSbsh * have firmware which doesn't interact properly with a imxuart device in
23815a80dc5fSbsh * FIFO mode.
23825a80dc5fSbsh */
23835a80dc5fSbsh struct imxuart_softc *sc = device_private(self);
23845a80dc5fSbsh
23855a80dc5fSbsh if (ISSET(sc->sc_hwflags, IMXUART_HW_FIFO))
23865a80dc5fSbsh UR_WRITE_1(&sc->sc_regs, IMXUART_REG_FIFO, 0);
23875a80dc5fSbsh
23885a80dc5fSbsh return true;
23895a80dc5fSbsh }
23905a80dc5fSbsh #endif
23915a80dc5fSbsh
23925a80dc5fSbsh #ifdef notyet
23935a80dc5fSbsh bool
imxuart_suspend(device_t self PMF_FN_ARGS)23945a80dc5fSbsh imxuart_suspend(device_t self PMF_FN_ARGS)
23955a80dc5fSbsh {
23965a80dc5fSbsh struct imxuart_softc *sc = device_private(self);
23975a80dc5fSbsh
23985a80dc5fSbsh UR_WRITE_1(&sc->sc_regs, IMXUART_REG_IER, 0);
23995a80dc5fSbsh (void)CSR_READ_1(&sc->sc_regs, IMXUART_REG_IIR);
24005a80dc5fSbsh
24015a80dc5fSbsh return true;
24025a80dc5fSbsh }
24035a80dc5fSbsh #endif
24045a80dc5fSbsh
24055a80dc5fSbsh #ifdef notyet
24065a80dc5fSbsh bool
imxuart_resume(device_t self PMF_FN_ARGS)24075a80dc5fSbsh imxuart_resume(device_t self PMF_FN_ARGS)
24085a80dc5fSbsh {
24095a80dc5fSbsh struct imxuart_softc *sc = device_private(self);
24105a80dc5fSbsh
24115a80dc5fSbsh mutex_spin_enter(&sc->sc_lock);
24125a80dc5fSbsh imxuart_loadchannelregs(sc);
24135a80dc5fSbsh mutex_spin_exit(&sc->sc_lock);
24145a80dc5fSbsh
24155a80dc5fSbsh return true;
24165a80dc5fSbsh }
24175a80dc5fSbsh #endif
24185a80dc5fSbsh
24195a80dc5fSbsh static void
imxuart_enable_debugport(struct imxuart_softc * sc)24205a80dc5fSbsh imxuart_enable_debugport(struct imxuart_softc *sc)
24215a80dc5fSbsh {
24225a80dc5fSbsh bus_space_tag_t iot = sc->sc_regs.ur_iot;
24235a80dc5fSbsh bus_space_handle_t ioh = sc->sc_regs.ur_ioh;
24245a80dc5fSbsh
24255a80dc5fSbsh if (sc->sc_hwflags & (IMXUART_HW_CONSOLE|IMXUART_HW_KGDB)) {
24265a80dc5fSbsh
24275a80dc5fSbsh /* Turn on line break interrupt, set carrier. */
24285a80dc5fSbsh
24295a80dc5fSbsh sc->sc_ucr3 |= IMX_UCR3_DSR;
24305a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR3, sc->sc_ucr3);
24315a80dc5fSbsh
24325a80dc5fSbsh sc->sc_ucr4 |= IMX_UCR4_BKEN;
24335a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR4, sc->sc_ucr4);
24345a80dc5fSbsh
24355a80dc5fSbsh sc->sc_ucr2 |= IMX_UCR2_TXEN|IMX_UCR2_RXEN|
24365a80dc5fSbsh IMX_UCR2_CTS;
24375a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR2, sc->sc_ucr2);
24385a80dc5fSbsh
24395a80dc5fSbsh sc->sc_ucr1 |= IMX_UCR1_UARTEN;
24405a80dc5fSbsh bus_space_write_4(iot, ioh, IMX_UCR1, sc->sc_ucr1);
24415a80dc5fSbsh }
24425a80dc5fSbsh }
24435a80dc5fSbsh
24445a80dc5fSbsh
24455a80dc5fSbsh void
imxuart_set_frequency(u_int freq,u_int div)24465a80dc5fSbsh imxuart_set_frequency(u_int freq, u_int div)
24475a80dc5fSbsh {
24485a80dc5fSbsh imxuart_freq = freq;
24495a80dc5fSbsh imxuart_freqdiv = div;
24505a80dc5fSbsh }
2451