xref: /netbsd-src/sys/arch/arm/imx/imxuart.c (revision dbfa10e52a5827a2b548912aaaea11468b4c7f47)
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, &regsp->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(&regs, 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