xref: /freebsd/sys/dev/uart/uart_dev_imx.c (revision c3f0f2847fbe3e138b2de1293a691effdd8e2ace)
1a2c472e7SAleksandr Rybalko /*-
2a2c472e7SAleksandr Rybalko  * Copyright (c) 2012 The FreeBSD Foundation
3a2c472e7SAleksandr Rybalko  * All rights reserved.
4a2c472e7SAleksandr Rybalko  *
5a2c472e7SAleksandr Rybalko  * This software was developed by Oleksandr Rybalko under sponsorship
6a2c472e7SAleksandr Rybalko  * from the FreeBSD Foundation.
7a2c472e7SAleksandr Rybalko  *
8a2c472e7SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
9a2c472e7SAleksandr Rybalko  * modification, are permitted provided that the following conditions
10a2c472e7SAleksandr Rybalko  * are met:
11a2c472e7SAleksandr Rybalko  * 1.	Redistributions of source code must retain the above copyright
12a2c472e7SAleksandr Rybalko  *	notice, this list of conditions and the following disclaimer.
13a2c472e7SAleksandr Rybalko  * 2.	Redistributions in binary form must reproduce the above copyright
14a2c472e7SAleksandr Rybalko  *	notice, this list of conditions and the following disclaimer in the
15a2c472e7SAleksandr Rybalko  *	documentation and/or other materials provided with the distribution.
16a2c472e7SAleksandr Rybalko  *
17a2c472e7SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18a2c472e7SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19a2c472e7SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20a2c472e7SAleksandr Rybalko  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21a2c472e7SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22a2c472e7SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23a2c472e7SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24a2c472e7SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25a2c472e7SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26a2c472e7SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27a2c472e7SAleksandr Rybalko  * SUCH DAMAGE.
28a2c472e7SAleksandr Rybalko  */
29a2c472e7SAleksandr Rybalko 
30a2c472e7SAleksandr Rybalko #include <sys/cdefs.h>
31a2c472e7SAleksandr Rybalko __FBSDID("$FreeBSD$");
32a2c472e7SAleksandr Rybalko 
33a2c472e7SAleksandr Rybalko #include "opt_ddb.h"
34a2c472e7SAleksandr Rybalko 
35a2c472e7SAleksandr Rybalko #include <sys/param.h>
36a2c472e7SAleksandr Rybalko #include <sys/systm.h>
37a2c472e7SAleksandr Rybalko #include <sys/bus.h>
38a2c472e7SAleksandr Rybalko #include <sys/conf.h>
39a2c472e7SAleksandr Rybalko #include <sys/kdb.h>
40a2c472e7SAleksandr Rybalko #include <machine/bus.h>
41a2c472e7SAleksandr Rybalko #include <machine/fdt.h>
42a2c472e7SAleksandr Rybalko 
43a2c472e7SAleksandr Rybalko #include <dev/uart/uart.h>
44a2c472e7SAleksandr Rybalko #include <dev/uart/uart_cpu.h>
45a2c472e7SAleksandr Rybalko #include <dev/uart/uart_bus.h>
46a90f1975SIan Lepore #include <dev/uart/uart_dev_imx.h>
47a2c472e7SAleksandr Rybalko #include "uart_if.h"
482d40ec16SIan Lepore 
492d40ec16SIan Lepore #include <arm/freescale/imx/imx_ccmvar.h>
502d40ec16SIan Lepore 
51a2c472e7SAleksandr Rybalko /*
52a2c472e7SAleksandr Rybalko  * Low-level UART interface.
53a2c472e7SAleksandr Rybalko  */
54a2c472e7SAleksandr Rybalko static int imx_uart_probe(struct uart_bas *bas);
55a2c472e7SAleksandr Rybalko static void imx_uart_init(struct uart_bas *bas, int, int, int, int);
56a2c472e7SAleksandr Rybalko static void imx_uart_term(struct uart_bas *bas);
57a2c472e7SAleksandr Rybalko static void imx_uart_putc(struct uart_bas *bas, int);
58a2c472e7SAleksandr Rybalko static int imx_uart_rxready(struct uart_bas *bas);
59a2c472e7SAleksandr Rybalko static int imx_uart_getc(struct uart_bas *bas, struct mtx *);
60a2c472e7SAleksandr Rybalko 
61a2c472e7SAleksandr Rybalko static struct uart_ops uart_imx_uart_ops = {
62a2c472e7SAleksandr Rybalko 	.probe = imx_uart_probe,
63a2c472e7SAleksandr Rybalko 	.init = imx_uart_init,
64a2c472e7SAleksandr Rybalko 	.term = imx_uart_term,
65a2c472e7SAleksandr Rybalko 	.putc = imx_uart_putc,
66a2c472e7SAleksandr Rybalko 	.rxready = imx_uart_rxready,
67a2c472e7SAleksandr Rybalko 	.getc = imx_uart_getc,
68a2c472e7SAleksandr Rybalko };
69a2c472e7SAleksandr Rybalko 
702d40ec16SIan Lepore #if 0 /* Handy when debugging. */
712d40ec16SIan Lepore static void
722d40ec16SIan Lepore dumpregs(struct uart_bas *bas, const char * msg)
732d40ec16SIan Lepore {
742d40ec16SIan Lepore 
752d40ec16SIan Lepore 	if (!bootverbose)
762d40ec16SIan Lepore 		return;
772d40ec16SIan Lepore 	printf("%s bsh 0x%08lx UCR1 0x%08x UCR2 0x%08x "
782d40ec16SIan Lepore 		"UCR3 0x%08x UCR4 0x%08x USR1 0x%08x USR2 0x%08x\n",
792d40ec16SIan Lepore 	    msg, bas->bsh,
802d40ec16SIan Lepore 	    GETREG(bas, REG(UCR1)), GETREG(bas, REG(UCR2)),
812d40ec16SIan Lepore 	    GETREG(bas, REG(UCR3)), GETREG(bas, REG(UCR4)),
822d40ec16SIan Lepore 	    GETREG(bas, REG(USR1)), GETREG(bas, REG(USR2)));
832d40ec16SIan Lepore }
842d40ec16SIan Lepore #endif
852d40ec16SIan Lepore 
86a2c472e7SAleksandr Rybalko static int
87a2c472e7SAleksandr Rybalko imx_uart_probe(struct uart_bas *bas)
88a2c472e7SAleksandr Rybalko {
89a2c472e7SAleksandr Rybalko 
90a2c472e7SAleksandr Rybalko 	return (0);
91a2c472e7SAleksandr Rybalko }
92a2c472e7SAleksandr Rybalko 
93*c3f0f284SIan Lepore static u_int
94*c3f0f284SIan Lepore imx_uart_getbaud(struct uart_bas *bas)
95*c3f0f284SIan Lepore {
96*c3f0f284SIan Lepore 	uint32_t rate, ubir, ubmr;
97*c3f0f284SIan Lepore 	u_int baud, blo, bhi, i;
98*c3f0f284SIan Lepore 	static const u_int predivs[] = {6, 5, 4, 3, 2, 1, 7, 1};
99*c3f0f284SIan Lepore 	static const u_int std_rates[] = {
100*c3f0f284SIan Lepore 		9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600
101*c3f0f284SIan Lepore 	};
102*c3f0f284SIan Lepore 
103*c3f0f284SIan Lepore 	/*
104*c3f0f284SIan Lepore 	 * Get the baud rate the hardware is programmed for, then search the
105*c3f0f284SIan Lepore 	 * table of standard baud rates for a number that's within 3% of the
106*c3f0f284SIan Lepore 	 * actual rate the hardware is programmed for.  It's more comforting to
107*c3f0f284SIan Lepore 	 * see that your console is running at 115200 than 114942.  Note that
108*c3f0f284SIan Lepore 	 * here we cannot make a simplifying assumption that the predivider and
109*c3f0f284SIan Lepore 	 * numerator are 1 (like we do when setting the baud rate), because we
110*c3f0f284SIan Lepore 	 * don't know what u-boot might have set up.
111*c3f0f284SIan Lepore 	 */
112*c3f0f284SIan Lepore 	i = (GETREG(bas, REG(UFCR)) & IMXUART_UFCR_RFDIV_MASK) >>
113*c3f0f284SIan Lepore 	    IMXUART_UFCR_RFDIV_SHIFT;
114*c3f0f284SIan Lepore 	rate = imx_ccm_uart_hz() / predivs[i];
115*c3f0f284SIan Lepore 	ubir = GETREG(bas, REG(UBIR)) + 1;
116*c3f0f284SIan Lepore 	ubmr = GETREG(bas, REG(UBMR)) + 1;
117*c3f0f284SIan Lepore 	baud = ((rate / 16 ) * ubir) / ubmr;
118*c3f0f284SIan Lepore 
119*c3f0f284SIan Lepore 	blo = (baud * 100) / 103;
120*c3f0f284SIan Lepore 	bhi = (baud * 100) / 97;
121*c3f0f284SIan Lepore 	for (i = 0; i < nitems(std_rates); i++) {
122*c3f0f284SIan Lepore 		rate = std_rates[i];
123*c3f0f284SIan Lepore 		if (rate >= blo && rate <= bhi) {
124*c3f0f284SIan Lepore 			baud = rate;
125*c3f0f284SIan Lepore 			break;
126*c3f0f284SIan Lepore 		}
127*c3f0f284SIan Lepore 	}
128*c3f0f284SIan Lepore 
129*c3f0f284SIan Lepore 	return (baud);
130*c3f0f284SIan Lepore }
131*c3f0f284SIan Lepore 
132a2c472e7SAleksandr Rybalko static void
133a2c472e7SAleksandr Rybalko imx_uart_init(struct uart_bas *bas, int baudrate, int databits,
134a2c472e7SAleksandr Rybalko     int stopbits, int parity)
135a2c472e7SAleksandr Rybalko {
1362d40ec16SIan Lepore 	uint32_t baseclk, reg;
137a2c472e7SAleksandr Rybalko 
1382d40ec16SIan Lepore         /* Enable the device and the RX/TX channels. */
1392d40ec16SIan Lepore 	SET(bas, REG(UCR1), FLD(UCR1, UARTEN));
1402d40ec16SIan Lepore 	SET(bas, REG(UCR2), FLD(UCR2, RXEN) | FLD(UCR2, TXEN));
1412d40ec16SIan Lepore 
1422d40ec16SIan Lepore 	if (databits == 7)
1432d40ec16SIan Lepore 		DIS(bas, UCR2, WS);
1442d40ec16SIan Lepore 	else
1452d40ec16SIan Lepore 		ENA(bas, UCR2, WS);
1462d40ec16SIan Lepore 
1472d40ec16SIan Lepore 	if (stopbits == 2)
1482d40ec16SIan Lepore 		ENA(bas, UCR2, STPB);
1492d40ec16SIan Lepore 	else
1502d40ec16SIan Lepore 		DIS(bas, UCR2, STPB);
1512d40ec16SIan Lepore 
1522d40ec16SIan Lepore 	switch (parity) {
1532d40ec16SIan Lepore 	case UART_PARITY_ODD:
1542d40ec16SIan Lepore 		DIS(bas, UCR2, PROE);
1552d40ec16SIan Lepore 		ENA(bas, UCR2, PREN);
1562d40ec16SIan Lepore 		break;
1572d40ec16SIan Lepore 	case UART_PARITY_EVEN:
1582d40ec16SIan Lepore 		ENA(bas, UCR2, PROE);
1592d40ec16SIan Lepore 		ENA(bas, UCR2, PREN);
1602d40ec16SIan Lepore 		break;
1612d40ec16SIan Lepore 	case UART_PARITY_MARK:
1622d40ec16SIan Lepore 	case UART_PARITY_SPACE:
1632d40ec16SIan Lepore                 /* FALLTHROUGH: Hardware doesn't support mark/space. */
1642d40ec16SIan Lepore 	case UART_PARITY_NONE:
1652d40ec16SIan Lepore 	default:
1662d40ec16SIan Lepore 		DIS(bas, UCR2, PREN);
1672d40ec16SIan Lepore 		break;
1682d40ec16SIan Lepore 	}
1692d40ec16SIan Lepore 
1702d40ec16SIan Lepore 	/*
1712d40ec16SIan Lepore 	 * The hardware has an extremely flexible baud clock: it allows setting
1722d40ec16SIan Lepore 	 * both the numerator and denominator of the divider, as well as a
17349d0a4c3SIan Lepore 	 * separate pre-divider.  We simplify the problem of coming up with a
17449d0a4c3SIan Lepore 	 * workable pair of numbers by assuming a pre-divider and numerator of
17549d0a4c3SIan Lepore 	 * one because our base clock is so fast we can reach virtually any
17649d0a4c3SIan Lepore 	 * reasonable speed with a simple divisor.  The numerator value actually
17749d0a4c3SIan Lepore 	 * includes the 16x over-sampling (so a value of 16 means divide by 1);
17849d0a4c3SIan Lepore 	 * the register value is the numerator-1, so we have a hard-coded 15.
17949d0a4c3SIan Lepore 	 * Note that a quirk of the hardware requires that both UBIR and UBMR be
18049d0a4c3SIan Lepore 	 * set back to back in order for the change to take effect.
1812d40ec16SIan Lepore 	 */
1822d40ec16SIan Lepore 	if (baudrate > 0) {
1832d40ec16SIan Lepore 		baseclk = imx_ccm_uart_hz();
1842d40ec16SIan Lepore 		reg = GETREG(bas, REG(UFCR));
1852d40ec16SIan Lepore 		reg = (reg & ~IMXUART_UFCR_RFDIV_MASK) | IMXUART_UFCR_RFDIV_DIV1;
1862d40ec16SIan Lepore 		SETREG(bas, REG(UFCR), reg);
1872d40ec16SIan Lepore 		SETREG(bas, REG(UBIR), 15);
1882d40ec16SIan Lepore 		SETREG(bas, REG(UBMR), (baseclk / baudrate) - 1);
1892d40ec16SIan Lepore 	}
190a2c472e7SAleksandr Rybalko }
191a2c472e7SAleksandr Rybalko 
192a2c472e7SAleksandr Rybalko static void
193a2c472e7SAleksandr Rybalko imx_uart_term(struct uart_bas *bas)
194a2c472e7SAleksandr Rybalko {
195a2c472e7SAleksandr Rybalko 
196a2c472e7SAleksandr Rybalko }
197a2c472e7SAleksandr Rybalko 
198a2c472e7SAleksandr Rybalko static void
199a2c472e7SAleksandr Rybalko imx_uart_putc(struct uart_bas *bas, int c)
200a2c472e7SAleksandr Rybalko {
201a2c472e7SAleksandr Rybalko 
202a2c472e7SAleksandr Rybalko 	while (!(IS(bas, USR2, TXFE)))
203a2c472e7SAleksandr Rybalko 		;
204a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(UTXD), c);
205a2c472e7SAleksandr Rybalko }
206a2c472e7SAleksandr Rybalko 
207a2c472e7SAleksandr Rybalko static int
208a2c472e7SAleksandr Rybalko imx_uart_rxready(struct uart_bas *bas)
209a2c472e7SAleksandr Rybalko {
210a2c472e7SAleksandr Rybalko 
211a2c472e7SAleksandr Rybalko 	return ((IS(bas, USR2, RDR)) ? 1 : 0);
212a2c472e7SAleksandr Rybalko }
213a2c472e7SAleksandr Rybalko 
214a2c472e7SAleksandr Rybalko static int
215a2c472e7SAleksandr Rybalko imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
216a2c472e7SAleksandr Rybalko {
217a2c472e7SAleksandr Rybalko 	int c;
218a2c472e7SAleksandr Rybalko 
219a2c472e7SAleksandr Rybalko 	uart_lock(hwmtx);
220a2c472e7SAleksandr Rybalko 	while (!(IS(bas, USR2, RDR)))
221a2c472e7SAleksandr Rybalko 		;
222a2c472e7SAleksandr Rybalko 
223a2c472e7SAleksandr Rybalko 	c = GETREG(bas, REG(URXD));
224a2c472e7SAleksandr Rybalko 	uart_unlock(hwmtx);
225a2c472e7SAleksandr Rybalko #if defined(KDB)
226a2c472e7SAleksandr Rybalko 	if (c & FLD(URXD, BRK)) {
227a2c472e7SAleksandr Rybalko 		if (kdb_break())
228a2c472e7SAleksandr Rybalko 			return (0);
229a2c472e7SAleksandr Rybalko 	}
230a2c472e7SAleksandr Rybalko #endif
231a2c472e7SAleksandr Rybalko 	return (c & 0xff);
232a2c472e7SAleksandr Rybalko }
233a2c472e7SAleksandr Rybalko 
234a2c472e7SAleksandr Rybalko /*
235a2c472e7SAleksandr Rybalko  * High-level UART interface.
236a2c472e7SAleksandr Rybalko  */
237a2c472e7SAleksandr Rybalko struct imx_uart_softc {
238a2c472e7SAleksandr Rybalko 	struct uart_softc base;
239a2c472e7SAleksandr Rybalko };
240a2c472e7SAleksandr Rybalko 
241a2c472e7SAleksandr Rybalko static int imx_uart_bus_attach(struct uart_softc *);
242a2c472e7SAleksandr Rybalko static int imx_uart_bus_detach(struct uart_softc *);
243a2c472e7SAleksandr Rybalko static int imx_uart_bus_flush(struct uart_softc *, int);
244a2c472e7SAleksandr Rybalko static int imx_uart_bus_getsig(struct uart_softc *);
245a2c472e7SAleksandr Rybalko static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
246a2c472e7SAleksandr Rybalko static int imx_uart_bus_ipend(struct uart_softc *);
247a2c472e7SAleksandr Rybalko static int imx_uart_bus_param(struct uart_softc *, int, int, int, int);
248a2c472e7SAleksandr Rybalko static int imx_uart_bus_probe(struct uart_softc *);
249a2c472e7SAleksandr Rybalko static int imx_uart_bus_receive(struct uart_softc *);
250a2c472e7SAleksandr Rybalko static int imx_uart_bus_setsig(struct uart_softc *, int);
251a2c472e7SAleksandr Rybalko static int imx_uart_bus_transmit(struct uart_softc *);
252d76a1ef4SWarner Losh static void imx_uart_bus_grab(struct uart_softc *);
253d76a1ef4SWarner Losh static void imx_uart_bus_ungrab(struct uart_softc *);
254a2c472e7SAleksandr Rybalko 
255a2c472e7SAleksandr Rybalko static kobj_method_t imx_uart_methods[] = {
256a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_attach,		imx_uart_bus_attach),
257a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_detach,		imx_uart_bus_detach),
258a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_flush,		imx_uart_bus_flush),
259a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_getsig,		imx_uart_bus_getsig),
260a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_ioctl,		imx_uart_bus_ioctl),
261a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_ipend,		imx_uart_bus_ipend),
262a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_param,		imx_uart_bus_param),
263a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_probe,		imx_uart_bus_probe),
264a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_receive,	imx_uart_bus_receive),
265a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_setsig,		imx_uart_bus_setsig),
266a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_transmit,	imx_uart_bus_transmit),
267d76a1ef4SWarner Losh 	KOBJMETHOD(uart_grab,		imx_uart_bus_grab),
268d76a1ef4SWarner Losh 	KOBJMETHOD(uart_ungrab,		imx_uart_bus_ungrab),
269a2c472e7SAleksandr Rybalko 	{ 0, 0 }
270a2c472e7SAleksandr Rybalko };
271a2c472e7SAleksandr Rybalko 
272a2c472e7SAleksandr Rybalko struct uart_class uart_imx_class = {
273a2c472e7SAleksandr Rybalko 	"imx",
274a2c472e7SAleksandr Rybalko 	imx_uart_methods,
275a2c472e7SAleksandr Rybalko 	sizeof(struct imx_uart_softc),
276a2c472e7SAleksandr Rybalko 	.uc_ops = &uart_imx_uart_ops,
277a2c472e7SAleksandr Rybalko 	.uc_range = 0x100,
278a2c472e7SAleksandr Rybalko 	.uc_rclk = 24000000 /* TODO: get value from CCM */
279a2c472e7SAleksandr Rybalko };
280a2c472e7SAleksandr Rybalko 
281a2c472e7SAleksandr Rybalko #define	SIGCHG(c, i, s, d)				\
282a2c472e7SAleksandr Rybalko 	if (c) {					\
283a2c472e7SAleksandr Rybalko 		i |= (i & s) ? s : s | d;		\
284a2c472e7SAleksandr Rybalko 	} else {					\
285a2c472e7SAleksandr Rybalko 		i = (i & s) ? (i & ~s) | d : i;		\
286a2c472e7SAleksandr Rybalko 	}
287a2c472e7SAleksandr Rybalko 
288a2c472e7SAleksandr Rybalko static int
289a2c472e7SAleksandr Rybalko imx_uart_bus_attach(struct uart_softc *sc)
290a2c472e7SAleksandr Rybalko {
291a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
292a2c472e7SAleksandr Rybalko 	struct uart_devinfo *di;
293a2c472e7SAleksandr Rybalko 
294a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
295a2c472e7SAleksandr Rybalko 	if (sc->sc_sysdev != NULL) {
296a2c472e7SAleksandr Rybalko 		di = sc->sc_sysdev;
297a2c472e7SAleksandr Rybalko 		imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
298a2c472e7SAleksandr Rybalko 		    di->parity);
299a2c472e7SAleksandr Rybalko 	} else {
300a2c472e7SAleksandr Rybalko 		imx_uart_init(bas, 115200, 8, 1, 0);
301a2c472e7SAleksandr Rybalko 	}
302a2c472e7SAleksandr Rybalko 
303a2c472e7SAleksandr Rybalko 	(void)imx_uart_bus_getsig(sc);
304a2c472e7SAleksandr Rybalko 
305a2c472e7SAleksandr Rybalko 	ENA(bas, UCR4, DREN);
306a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, RRDYEN);
307a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, IDEN);
308a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, RXDSEN);
309a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, ATEN);
310a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, TXMPTYEN);
311a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, TRDYEN);
312a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, TCEN);
313a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, OREN);
314a2c472e7SAleksandr Rybalko 	ENA(bas, UCR4, BKEN);
315a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, WKEN);
316a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, ADEN);
317a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, ACIEN);
318a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, ESCI);
319a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, ENIRI);
320a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, AIRINTEN);
321a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, AWAKEN);
322a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, FRAERREN);
323a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, PARERREN);
324a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, RTSDEN);
325a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, RTSEN);
326a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DTREN);
327a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, RI);
328a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DCD);
329a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DTRDEN);
3302d40ec16SIan Lepore 	ENA(bas, UCR2, IRTS);
3312d40ec16SIan Lepore 	ENA(bas, UCR3, RXDMUXSEL);
332a2c472e7SAleksandr Rybalko 
333a2c472e7SAleksandr Rybalko 	/* ACK all interrupts */
334a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR1), 0xffff);
335a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR2), 0xffff);
336a2c472e7SAleksandr Rybalko 	return (0);
337a2c472e7SAleksandr Rybalko }
338a2c472e7SAleksandr Rybalko 
339a2c472e7SAleksandr Rybalko static int
340a2c472e7SAleksandr Rybalko imx_uart_bus_detach(struct uart_softc *sc)
341a2c472e7SAleksandr Rybalko {
342a2c472e7SAleksandr Rybalko 
343a2c472e7SAleksandr Rybalko 	SETREG(&sc->sc_bas, REG(UCR4), 0);
344a2c472e7SAleksandr Rybalko 
345a2c472e7SAleksandr Rybalko 	return (0);
346a2c472e7SAleksandr Rybalko }
347a2c472e7SAleksandr Rybalko 
348a2c472e7SAleksandr Rybalko static int
349a2c472e7SAleksandr Rybalko imx_uart_bus_flush(struct uart_softc *sc, int what)
350a2c472e7SAleksandr Rybalko {
351a2c472e7SAleksandr Rybalko 
352a2c472e7SAleksandr Rybalko 	/* TODO */
353a2c472e7SAleksandr Rybalko 	return (0);
354a2c472e7SAleksandr Rybalko }
355a2c472e7SAleksandr Rybalko 
356a2c472e7SAleksandr Rybalko static int
357a2c472e7SAleksandr Rybalko imx_uart_bus_getsig(struct uart_softc *sc)
358a2c472e7SAleksandr Rybalko {
359a2c472e7SAleksandr Rybalko 	uint32_t new, old, sig;
360a2c472e7SAleksandr Rybalko 	uint8_t bes;
361a2c472e7SAleksandr Rybalko 
362a2c472e7SAleksandr Rybalko 	do {
363a2c472e7SAleksandr Rybalko 		old = sc->sc_hwsig;
364a2c472e7SAleksandr Rybalko 		sig = old;
365a2c472e7SAleksandr Rybalko 		uart_lock(sc->sc_hwmtx);
366a2c472e7SAleksandr Rybalko 		bes = GETREG(&sc->sc_bas, REG(USR2));
367a2c472e7SAleksandr Rybalko 		uart_unlock(sc->sc_hwmtx);
368a2c472e7SAleksandr Rybalko 		/* XXX: chip can show delta */
369a2c472e7SAleksandr Rybalko 		SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD);
370a2c472e7SAleksandr Rybalko 		new = sig & ~SER_MASK_DELTA;
371a2c472e7SAleksandr Rybalko 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
372a2c472e7SAleksandr Rybalko 
373a2c472e7SAleksandr Rybalko 	return (sig);
374a2c472e7SAleksandr Rybalko }
375a2c472e7SAleksandr Rybalko 
376a2c472e7SAleksandr Rybalko static int
377a2c472e7SAleksandr Rybalko imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
378a2c472e7SAleksandr Rybalko {
379a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
380a2c472e7SAleksandr Rybalko 	int error;
381a2c472e7SAleksandr Rybalko 
382a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
383a2c472e7SAleksandr Rybalko 	error = 0;
384a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
385a2c472e7SAleksandr Rybalko 	switch (request) {
386a2c472e7SAleksandr Rybalko 	case UART_IOCTL_BREAK:
387a2c472e7SAleksandr Rybalko 		/* TODO */
388a2c472e7SAleksandr Rybalko 		break;
389a2c472e7SAleksandr Rybalko 	case UART_IOCTL_BAUD:
390*c3f0f284SIan Lepore 		*(u_int*)data = imx_uart_getbaud(bas);
391a2c472e7SAleksandr Rybalko 		break;
392a2c472e7SAleksandr Rybalko 	default:
393a2c472e7SAleksandr Rybalko 		error = EINVAL;
394a2c472e7SAleksandr Rybalko 		break;
395a2c472e7SAleksandr Rybalko 	}
396a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
397a2c472e7SAleksandr Rybalko 
398a2c472e7SAleksandr Rybalko 	return (error);
399a2c472e7SAleksandr Rybalko }
400a2c472e7SAleksandr Rybalko 
401a2c472e7SAleksandr Rybalko static int
402a2c472e7SAleksandr Rybalko imx_uart_bus_ipend(struct uart_softc *sc)
403a2c472e7SAleksandr Rybalko {
404a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
405a2c472e7SAleksandr Rybalko 	int ipend;
406a2c472e7SAleksandr Rybalko 	uint32_t usr1, usr2;
407a2c472e7SAleksandr Rybalko 	uint32_t ucr1, ucr4;
408a2c472e7SAleksandr Rybalko 
409a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
410a2c472e7SAleksandr Rybalko 	ipend = 0;
411a2c472e7SAleksandr Rybalko 
412a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
413a2c472e7SAleksandr Rybalko 
414a2c472e7SAleksandr Rybalko 	/* Read pending interrupts */
415a2c472e7SAleksandr Rybalko 	usr1 = GETREG(bas, REG(USR1));
416a2c472e7SAleksandr Rybalko 	usr2 = GETREG(bas, REG(USR2));
417a2c472e7SAleksandr Rybalko 	/* ACK interrupts */
418a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR1), usr1);
419a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR2), usr2);
420a2c472e7SAleksandr Rybalko 
421a2c472e7SAleksandr Rybalko 	ucr1 = GETREG(bas, REG(UCR1));
422a2c472e7SAleksandr Rybalko 	ucr4 = GETREG(bas, REG(UCR4));
423a2c472e7SAleksandr Rybalko 
424a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) {
425a2c472e7SAleksandr Rybalko 		DIS(bas, UCR1, TXMPTYEN);
426a2c472e7SAleksandr Rybalko 		/* Continue TXing */
427a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_TXIDLE;
428a2c472e7SAleksandr Rybalko 	}
429a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) {
430a2c472e7SAleksandr Rybalko 		DIS(bas, UCR4, DREN);
431a2c472e7SAleksandr Rybalko 		/* Wow, new char on input */
432a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_RXREADY;
433a2c472e7SAleksandr Rybalko 	}
434a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN)))
435a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_BREAK;
436a2c472e7SAleksandr Rybalko 
437a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
438a2c472e7SAleksandr Rybalko 
439a2c472e7SAleksandr Rybalko 	return (ipend);
440a2c472e7SAleksandr Rybalko }
441a2c472e7SAleksandr Rybalko 
442a2c472e7SAleksandr Rybalko static int
443a2c472e7SAleksandr Rybalko imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
444a2c472e7SAleksandr Rybalko     int stopbits, int parity)
445a2c472e7SAleksandr Rybalko {
446a2c472e7SAleksandr Rybalko 
447a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
448a2c472e7SAleksandr Rybalko 	imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
449a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
450a2c472e7SAleksandr Rybalko 	return (0);
451a2c472e7SAleksandr Rybalko }
452a2c472e7SAleksandr Rybalko 
453a2c472e7SAleksandr Rybalko static int
454a2c472e7SAleksandr Rybalko imx_uart_bus_probe(struct uart_softc *sc)
455a2c472e7SAleksandr Rybalko {
456a2c472e7SAleksandr Rybalko 	int error;
457a2c472e7SAleksandr Rybalko 
458a2c472e7SAleksandr Rybalko 	error = imx_uart_probe(&sc->sc_bas);
459a2c472e7SAleksandr Rybalko 	if (error)
460a2c472e7SAleksandr Rybalko 		return (error);
461a2c472e7SAleksandr Rybalko 
4624d7abca0SIan Lepore 	sc->sc_rxfifosz = 1;
4634d7abca0SIan Lepore 	sc->sc_txfifosz = 1;
4644d7abca0SIan Lepore 
4653329109cSRui Paulo 	device_set_desc(sc->sc_dev, "Freescale i.MX UART");
466a2c472e7SAleksandr Rybalko 	return (0);
467a2c472e7SAleksandr Rybalko }
468a2c472e7SAleksandr Rybalko 
469a2c472e7SAleksandr Rybalko static int
470a2c472e7SAleksandr Rybalko imx_uart_bus_receive(struct uart_softc *sc)
471a2c472e7SAleksandr Rybalko {
472a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
473a2c472e7SAleksandr Rybalko 	int xc, out;
474a2c472e7SAleksandr Rybalko 
475a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
476a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
477a2c472e7SAleksandr Rybalko 
478a2c472e7SAleksandr Rybalko 	/* Read while we have anything in FIFO */
479a2c472e7SAleksandr Rybalko 	while (IS(bas, USR2, RDR)) {
480a2c472e7SAleksandr Rybalko 		if (uart_rx_full(sc)) {
481a2c472e7SAleksandr Rybalko 			/* No space left in input buffer */
482a2c472e7SAleksandr Rybalko 			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
483a2c472e7SAleksandr Rybalko 			break;
484a2c472e7SAleksandr Rybalko 		}
485a2c472e7SAleksandr Rybalko 		out = 0;
486a2c472e7SAleksandr Rybalko 		xc = GETREG(bas, REG(URXD));
487a2c472e7SAleksandr Rybalko 
488a2c472e7SAleksandr Rybalko 		/* We have valid char */
489a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, CHARRDY))
490a2c472e7SAleksandr Rybalko 			out = xc & 0x000000ff;
491a2c472e7SAleksandr Rybalko 
492a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, FRMERR))
493a2c472e7SAleksandr Rybalko 			out |= UART_STAT_FRAMERR;
494a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, PRERR))
495a2c472e7SAleksandr Rybalko 			out |= UART_STAT_PARERR;
496a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, OVRRUN))
497a2c472e7SAleksandr Rybalko 			out |= UART_STAT_OVERRUN;
498a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, BRK))
499a2c472e7SAleksandr Rybalko 			out |= UART_STAT_BREAK;
500a2c472e7SAleksandr Rybalko 
501a2c472e7SAleksandr Rybalko 		uart_rx_put(sc, out);
502a2c472e7SAleksandr Rybalko 	}
503a2c472e7SAleksandr Rybalko 	/* Reenable Data Ready interrupt */
504a2c472e7SAleksandr Rybalko 	ENA(bas, UCR4, DREN);
505a2c472e7SAleksandr Rybalko 
506a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
507a2c472e7SAleksandr Rybalko 	return (0);
508a2c472e7SAleksandr Rybalko }
509a2c472e7SAleksandr Rybalko 
510a2c472e7SAleksandr Rybalko static int
511a2c472e7SAleksandr Rybalko imx_uart_bus_setsig(struct uart_softc *sc, int sig)
512a2c472e7SAleksandr Rybalko {
513a2c472e7SAleksandr Rybalko 
514a2c472e7SAleksandr Rybalko 	return (0);
515a2c472e7SAleksandr Rybalko }
516a2c472e7SAleksandr Rybalko 
517a2c472e7SAleksandr Rybalko static int
518a2c472e7SAleksandr Rybalko imx_uart_bus_transmit(struct uart_softc *sc)
519a2c472e7SAleksandr Rybalko {
520a2c472e7SAleksandr Rybalko 	struct uart_bas *bas = &sc->sc_bas;
521a2c472e7SAleksandr Rybalko 	int i;
522a2c472e7SAleksandr Rybalko 
523a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
524a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
525a2c472e7SAleksandr Rybalko 
526a2c472e7SAleksandr Rybalko 	/* Fill TX FIFO */
527a2c472e7SAleksandr Rybalko 	for (i = 0; i < sc->sc_txdatasz; i++) {
528a2c472e7SAleksandr Rybalko 		SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff);
529a2c472e7SAleksandr Rybalko 	}
530a2c472e7SAleksandr Rybalko 
531a2c472e7SAleksandr Rybalko 	sc->sc_txbusy = 1;
532a2c472e7SAleksandr Rybalko 	/* Call me when ready */
533a2c472e7SAleksandr Rybalko 	ENA(bas, UCR1, TXMPTYEN);
534a2c472e7SAleksandr Rybalko 
535a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
536a2c472e7SAleksandr Rybalko 
537a2c472e7SAleksandr Rybalko 	return (0);
538a2c472e7SAleksandr Rybalko }
539d76a1ef4SWarner Losh 
540d76a1ef4SWarner Losh static void
541d76a1ef4SWarner Losh imx_uart_bus_grab(struct uart_softc *sc)
542d76a1ef4SWarner Losh {
543d76a1ef4SWarner Losh 	struct uart_bas *bas = &sc->sc_bas;
544d76a1ef4SWarner Losh 
545d76a1ef4SWarner Losh 	bas = &sc->sc_bas;
546d76a1ef4SWarner Losh 	uart_lock(sc->sc_hwmtx);
547d76a1ef4SWarner Losh 	DIS(bas, UCR4, DREN);
548d76a1ef4SWarner Losh 	uart_unlock(sc->sc_hwmtx);
549d76a1ef4SWarner Losh }
550d76a1ef4SWarner Losh 
551d76a1ef4SWarner Losh static void
552d76a1ef4SWarner Losh imx_uart_bus_ungrab(struct uart_softc *sc)
553d76a1ef4SWarner Losh {
554d76a1ef4SWarner Losh 	struct uart_bas *bas = &sc->sc_bas;
555d76a1ef4SWarner Losh 
556d76a1ef4SWarner Losh 	bas = &sc->sc_bas;
557d76a1ef4SWarner Losh 	uart_lock(sc->sc_hwmtx);
558d76a1ef4SWarner Losh 	ENA(bas, UCR4, DREN);
559d76a1ef4SWarner Losh 	uart_unlock(sc->sc_hwmtx);
560d76a1ef4SWarner Losh }
561