xref: /freebsd/sys/dev/uart/uart_dev_imx.c (revision a2c472e741ff8682553464270bdef82b70635fdb)
1*a2c472e7SAleksandr Rybalko /*-
2*a2c472e7SAleksandr Rybalko  * Copyright (c) 2012 The FreeBSD Foundation
3*a2c472e7SAleksandr Rybalko  * All rights reserved.
4*a2c472e7SAleksandr Rybalko  *
5*a2c472e7SAleksandr Rybalko  * This software was developed by Oleksandr Rybalko under sponsorship
6*a2c472e7SAleksandr Rybalko  * from the FreeBSD Foundation.
7*a2c472e7SAleksandr Rybalko  *
8*a2c472e7SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
9*a2c472e7SAleksandr Rybalko  * modification, are permitted provided that the following conditions
10*a2c472e7SAleksandr Rybalko  * are met:
11*a2c472e7SAleksandr Rybalko  * 1.	Redistributions of source code must retain the above copyright
12*a2c472e7SAleksandr Rybalko  *	notice, this list of conditions and the following disclaimer.
13*a2c472e7SAleksandr Rybalko  * 2.	Redistributions in binary form must reproduce the above copyright
14*a2c472e7SAleksandr Rybalko  *	notice, this list of conditions and the following disclaimer in the
15*a2c472e7SAleksandr Rybalko  *	documentation and/or other materials provided with the distribution.
16*a2c472e7SAleksandr Rybalko  *
17*a2c472e7SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*a2c472e7SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*a2c472e7SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*a2c472e7SAleksandr Rybalko  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*a2c472e7SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*a2c472e7SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*a2c472e7SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*a2c472e7SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*a2c472e7SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*a2c472e7SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*a2c472e7SAleksandr Rybalko  * SUCH DAMAGE.
28*a2c472e7SAleksandr Rybalko  */
29*a2c472e7SAleksandr Rybalko 
30*a2c472e7SAleksandr Rybalko #include <sys/cdefs.h>
31*a2c472e7SAleksandr Rybalko __FBSDID("$FreeBSD$");
32*a2c472e7SAleksandr Rybalko 
33*a2c472e7SAleksandr Rybalko #include "opt_ddb.h"
34*a2c472e7SAleksandr Rybalko 
35*a2c472e7SAleksandr Rybalko #include <sys/param.h>
36*a2c472e7SAleksandr Rybalko #include <sys/systm.h>
37*a2c472e7SAleksandr Rybalko #include <sys/bus.h>
38*a2c472e7SAleksandr Rybalko #include <sys/conf.h>
39*a2c472e7SAleksandr Rybalko #include <sys/kdb.h>
40*a2c472e7SAleksandr Rybalko #include <machine/bus.h>
41*a2c472e7SAleksandr Rybalko #include <machine/fdt.h>
42*a2c472e7SAleksandr Rybalko 
43*a2c472e7SAleksandr Rybalko #include <dev/uart/uart.h>
44*a2c472e7SAleksandr Rybalko #include <dev/uart/uart_cpu.h>
45*a2c472e7SAleksandr Rybalko #include <dev/uart/uart_bus.h>
46*a2c472e7SAleksandr Rybalko 
47*a2c472e7SAleksandr Rybalko #include <dev/uart/uart_dev_imx5xx.h>
48*a2c472e7SAleksandr Rybalko 
49*a2c472e7SAleksandr Rybalko #include "uart_if.h"
50*a2c472e7SAleksandr Rybalko /*
51*a2c472e7SAleksandr Rybalko  * Low-level UART interface.
52*a2c472e7SAleksandr Rybalko  */
53*a2c472e7SAleksandr Rybalko static int imx_uart_probe(struct uart_bas *bas);
54*a2c472e7SAleksandr Rybalko static void imx_uart_init(struct uart_bas *bas, int, int, int, int);
55*a2c472e7SAleksandr Rybalko static void imx_uart_term(struct uart_bas *bas);
56*a2c472e7SAleksandr Rybalko static void imx_uart_putc(struct uart_bas *bas, int);
57*a2c472e7SAleksandr Rybalko static int imx_uart_rxready(struct uart_bas *bas);
58*a2c472e7SAleksandr Rybalko static int imx_uart_getc(struct uart_bas *bas, struct mtx *);
59*a2c472e7SAleksandr Rybalko 
60*a2c472e7SAleksandr Rybalko static struct uart_ops uart_imx_uart_ops = {
61*a2c472e7SAleksandr Rybalko 	.probe = imx_uart_probe,
62*a2c472e7SAleksandr Rybalko 	.init = imx_uart_init,
63*a2c472e7SAleksandr Rybalko 	.term = imx_uart_term,
64*a2c472e7SAleksandr Rybalko 	.putc = imx_uart_putc,
65*a2c472e7SAleksandr Rybalko 	.rxready = imx_uart_rxready,
66*a2c472e7SAleksandr Rybalko 	.getc = imx_uart_getc,
67*a2c472e7SAleksandr Rybalko };
68*a2c472e7SAleksandr Rybalko 
69*a2c472e7SAleksandr Rybalko static int
70*a2c472e7SAleksandr Rybalko imx_uart_probe(struct uart_bas *bas)
71*a2c472e7SAleksandr Rybalko {
72*a2c472e7SAleksandr Rybalko 
73*a2c472e7SAleksandr Rybalko 	return (0);
74*a2c472e7SAleksandr Rybalko }
75*a2c472e7SAleksandr Rybalko 
76*a2c472e7SAleksandr Rybalko static void
77*a2c472e7SAleksandr Rybalko imx_uart_init(struct uart_bas *bas, int baudrate, int databits,
78*a2c472e7SAleksandr Rybalko     int stopbits, int parity)
79*a2c472e7SAleksandr Rybalko {
80*a2c472e7SAleksandr Rybalko 
81*a2c472e7SAleksandr Rybalko }
82*a2c472e7SAleksandr Rybalko 
83*a2c472e7SAleksandr Rybalko static void
84*a2c472e7SAleksandr Rybalko imx_uart_term(struct uart_bas *bas)
85*a2c472e7SAleksandr Rybalko {
86*a2c472e7SAleksandr Rybalko 
87*a2c472e7SAleksandr Rybalko }
88*a2c472e7SAleksandr Rybalko 
89*a2c472e7SAleksandr Rybalko static void
90*a2c472e7SAleksandr Rybalko imx_uart_putc(struct uart_bas *bas, int c)
91*a2c472e7SAleksandr Rybalko {
92*a2c472e7SAleksandr Rybalko 
93*a2c472e7SAleksandr Rybalko 	while (!(IS(bas, USR2, TXFE)))
94*a2c472e7SAleksandr Rybalko 		;
95*a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(UTXD), c);
96*a2c472e7SAleksandr Rybalko }
97*a2c472e7SAleksandr Rybalko 
98*a2c472e7SAleksandr Rybalko static int
99*a2c472e7SAleksandr Rybalko imx_uart_rxready(struct uart_bas *bas)
100*a2c472e7SAleksandr Rybalko {
101*a2c472e7SAleksandr Rybalko 
102*a2c472e7SAleksandr Rybalko 	return ((IS(bas, USR2, RDR)) ? 1 : 0);
103*a2c472e7SAleksandr Rybalko }
104*a2c472e7SAleksandr Rybalko 
105*a2c472e7SAleksandr Rybalko static int
106*a2c472e7SAleksandr Rybalko imx_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
107*a2c472e7SAleksandr Rybalko {
108*a2c472e7SAleksandr Rybalko 	int c;
109*a2c472e7SAleksandr Rybalko 
110*a2c472e7SAleksandr Rybalko 	uart_lock(hwmtx);
111*a2c472e7SAleksandr Rybalko 	while (!(IS(bas, USR2, RDR)))
112*a2c472e7SAleksandr Rybalko 		;
113*a2c472e7SAleksandr Rybalko 
114*a2c472e7SAleksandr Rybalko 	c = GETREG(bas, REG(URXD));
115*a2c472e7SAleksandr Rybalko 	uart_unlock(hwmtx);
116*a2c472e7SAleksandr Rybalko #if defined(KDB)
117*a2c472e7SAleksandr Rybalko 	if (c & FLD(URXD, BRK)) {
118*a2c472e7SAleksandr Rybalko 		if (kdb_break())
119*a2c472e7SAleksandr Rybalko 			return (0);
120*a2c472e7SAleksandr Rybalko 	}
121*a2c472e7SAleksandr Rybalko #endif
122*a2c472e7SAleksandr Rybalko 	return (c & 0xff);
123*a2c472e7SAleksandr Rybalko }
124*a2c472e7SAleksandr Rybalko 
125*a2c472e7SAleksandr Rybalko /*
126*a2c472e7SAleksandr Rybalko  * High-level UART interface.
127*a2c472e7SAleksandr Rybalko  */
128*a2c472e7SAleksandr Rybalko struct imx_uart_softc {
129*a2c472e7SAleksandr Rybalko 	struct uart_softc base;
130*a2c472e7SAleksandr Rybalko };
131*a2c472e7SAleksandr Rybalko 
132*a2c472e7SAleksandr Rybalko static int imx_uart_bus_attach(struct uart_softc *);
133*a2c472e7SAleksandr Rybalko static int imx_uart_bus_detach(struct uart_softc *);
134*a2c472e7SAleksandr Rybalko static int imx_uart_bus_flush(struct uart_softc *, int);
135*a2c472e7SAleksandr Rybalko static int imx_uart_bus_getsig(struct uart_softc *);
136*a2c472e7SAleksandr Rybalko static int imx_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
137*a2c472e7SAleksandr Rybalko static int imx_uart_bus_ipend(struct uart_softc *);
138*a2c472e7SAleksandr Rybalko static int imx_uart_bus_param(struct uart_softc *, int, int, int, int);
139*a2c472e7SAleksandr Rybalko static int imx_uart_bus_probe(struct uart_softc *);
140*a2c472e7SAleksandr Rybalko static int imx_uart_bus_receive(struct uart_softc *);
141*a2c472e7SAleksandr Rybalko static int imx_uart_bus_setsig(struct uart_softc *, int);
142*a2c472e7SAleksandr Rybalko static int imx_uart_bus_transmit(struct uart_softc *);
143*a2c472e7SAleksandr Rybalko 
144*a2c472e7SAleksandr Rybalko static kobj_method_t imx_uart_methods[] = {
145*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_attach,		imx_uart_bus_attach),
146*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_detach,		imx_uart_bus_detach),
147*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_flush,		imx_uart_bus_flush),
148*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_getsig,		imx_uart_bus_getsig),
149*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_ioctl,		imx_uart_bus_ioctl),
150*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_ipend,		imx_uart_bus_ipend),
151*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_param,		imx_uart_bus_param),
152*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_probe,		imx_uart_bus_probe),
153*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_receive,	imx_uart_bus_receive),
154*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_setsig,		imx_uart_bus_setsig),
155*a2c472e7SAleksandr Rybalko 	KOBJMETHOD(uart_transmit,	imx_uart_bus_transmit),
156*a2c472e7SAleksandr Rybalko 	{ 0, 0 }
157*a2c472e7SAleksandr Rybalko };
158*a2c472e7SAleksandr Rybalko 
159*a2c472e7SAleksandr Rybalko struct uart_class uart_imx_class = {
160*a2c472e7SAleksandr Rybalko 	"imx",
161*a2c472e7SAleksandr Rybalko 	imx_uart_methods,
162*a2c472e7SAleksandr Rybalko 	sizeof(struct imx_uart_softc),
163*a2c472e7SAleksandr Rybalko 	.uc_ops = &uart_imx_uart_ops,
164*a2c472e7SAleksandr Rybalko 	.uc_range = 0x100,
165*a2c472e7SAleksandr Rybalko 	.uc_rclk = 24000000 /* TODO: get value from CCM */
166*a2c472e7SAleksandr Rybalko };
167*a2c472e7SAleksandr Rybalko 
168*a2c472e7SAleksandr Rybalko #define	SIGCHG(c, i, s, d)				\
169*a2c472e7SAleksandr Rybalko 	if (c) {					\
170*a2c472e7SAleksandr Rybalko 		i |= (i & s) ? s : s | d;		\
171*a2c472e7SAleksandr Rybalko 	} else {					\
172*a2c472e7SAleksandr Rybalko 		i = (i & s) ? (i & ~s) | d : i;		\
173*a2c472e7SAleksandr Rybalko 	}
174*a2c472e7SAleksandr Rybalko 
175*a2c472e7SAleksandr Rybalko static int
176*a2c472e7SAleksandr Rybalko imx_uart_bus_attach(struct uart_softc *sc)
177*a2c472e7SAleksandr Rybalko {
178*a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
179*a2c472e7SAleksandr Rybalko 	struct uart_devinfo *di;
180*a2c472e7SAleksandr Rybalko 
181*a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
182*a2c472e7SAleksandr Rybalko 	if (sc->sc_sysdev != NULL) {
183*a2c472e7SAleksandr Rybalko 		di = sc->sc_sysdev;
184*a2c472e7SAleksandr Rybalko 		imx_uart_init(bas, di->baudrate, di->databits, di->stopbits,
185*a2c472e7SAleksandr Rybalko 		    di->parity);
186*a2c472e7SAleksandr Rybalko 	} else {
187*a2c472e7SAleksandr Rybalko 		imx_uart_init(bas, 115200, 8, 1, 0);
188*a2c472e7SAleksandr Rybalko 	}
189*a2c472e7SAleksandr Rybalko 
190*a2c472e7SAleksandr Rybalko 	sc->sc_rxfifosz = 1;
191*a2c472e7SAleksandr Rybalko 	sc->sc_txfifosz = 1;
192*a2c472e7SAleksandr Rybalko 
193*a2c472e7SAleksandr Rybalko 	(void)imx_uart_bus_getsig(sc);
194*a2c472e7SAleksandr Rybalko 
195*a2c472e7SAleksandr Rybalko 	/* XXX workaround to have working console on manut prompt */
196*a2c472e7SAleksandr Rybalko 	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE){
197*a2c472e7SAleksandr Rybalko 		DIS(bas, UCR4, DREN);
198*a2c472e7SAleksandr Rybalko 	} else {
199*a2c472e7SAleksandr Rybalko 		ENA(bas, UCR4, DREN);
200*a2c472e7SAleksandr Rybalko 	}
201*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, RRDYEN);
202*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, IDEN);
203*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, RXDSEN);
204*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, ATEN);
205*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, TXMPTYEN);
206*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, TRDYEN);
207*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, TCEN);
208*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, OREN);
209*a2c472e7SAleksandr Rybalko 	ENA(bas, UCR4, BKEN);
210*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, WKEN);
211*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, ADEN);
212*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, ACIEN);
213*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, ESCI);
214*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR4, ENIRI);
215*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, AIRINTEN);
216*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, AWAKEN);
217*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, FRAERREN);
218*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, PARERREN);
219*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR1, RTSDEN);
220*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR2, RTSEN);
221*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DTREN);
222*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, RI);
223*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DCD);
224*a2c472e7SAleksandr Rybalko 	DIS(bas, UCR3, DTRDEN);
225*a2c472e7SAleksandr Rybalko 
226*a2c472e7SAleksandr Rybalko 	/* ACK all interrupts */
227*a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR1), 0xffff);
228*a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR2), 0xffff);
229*a2c472e7SAleksandr Rybalko 	return (0);
230*a2c472e7SAleksandr Rybalko }
231*a2c472e7SAleksandr Rybalko 
232*a2c472e7SAleksandr Rybalko static int
233*a2c472e7SAleksandr Rybalko imx_uart_bus_detach(struct uart_softc *sc)
234*a2c472e7SAleksandr Rybalko {
235*a2c472e7SAleksandr Rybalko 
236*a2c472e7SAleksandr Rybalko 	SETREG(&sc->sc_bas, REG(UCR4), 0);
237*a2c472e7SAleksandr Rybalko 
238*a2c472e7SAleksandr Rybalko 	return (0);
239*a2c472e7SAleksandr Rybalko }
240*a2c472e7SAleksandr Rybalko 
241*a2c472e7SAleksandr Rybalko static int
242*a2c472e7SAleksandr Rybalko imx_uart_bus_flush(struct uart_softc *sc, int what)
243*a2c472e7SAleksandr Rybalko {
244*a2c472e7SAleksandr Rybalko 
245*a2c472e7SAleksandr Rybalko 	/* TODO */
246*a2c472e7SAleksandr Rybalko 	return (0);
247*a2c472e7SAleksandr Rybalko }
248*a2c472e7SAleksandr Rybalko 
249*a2c472e7SAleksandr Rybalko static int
250*a2c472e7SAleksandr Rybalko imx_uart_bus_getsig(struct uart_softc *sc)
251*a2c472e7SAleksandr Rybalko {
252*a2c472e7SAleksandr Rybalko 	uint32_t new, old, sig;
253*a2c472e7SAleksandr Rybalko 	uint8_t bes;
254*a2c472e7SAleksandr Rybalko 
255*a2c472e7SAleksandr Rybalko 	do {
256*a2c472e7SAleksandr Rybalko 		old = sc->sc_hwsig;
257*a2c472e7SAleksandr Rybalko 		sig = old;
258*a2c472e7SAleksandr Rybalko 		uart_lock(sc->sc_hwmtx);
259*a2c472e7SAleksandr Rybalko 		bes = GETREG(&sc->sc_bas, REG(USR2));
260*a2c472e7SAleksandr Rybalko 		uart_unlock(sc->sc_hwmtx);
261*a2c472e7SAleksandr Rybalko 		/* XXX: chip can show delta */
262*a2c472e7SAleksandr Rybalko 		SIGCHG(bes & FLD(USR2, DCDIN), sig, SER_DCD, SER_DDCD);
263*a2c472e7SAleksandr Rybalko 		new = sig & ~SER_MASK_DELTA;
264*a2c472e7SAleksandr Rybalko 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
265*a2c472e7SAleksandr Rybalko 
266*a2c472e7SAleksandr Rybalko 	return (sig);
267*a2c472e7SAleksandr Rybalko }
268*a2c472e7SAleksandr Rybalko 
269*a2c472e7SAleksandr Rybalko static int
270*a2c472e7SAleksandr Rybalko imx_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
271*a2c472e7SAleksandr Rybalko {
272*a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
273*a2c472e7SAleksandr Rybalko 	int error;
274*a2c472e7SAleksandr Rybalko 
275*a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
276*a2c472e7SAleksandr Rybalko 	error = 0;
277*a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
278*a2c472e7SAleksandr Rybalko 	switch (request) {
279*a2c472e7SAleksandr Rybalko 	case UART_IOCTL_BREAK:
280*a2c472e7SAleksandr Rybalko 		/* TODO */
281*a2c472e7SAleksandr Rybalko 		break;
282*a2c472e7SAleksandr Rybalko 	case UART_IOCTL_BAUD:
283*a2c472e7SAleksandr Rybalko 		/* TODO */
284*a2c472e7SAleksandr Rybalko 		*(int*)data = 115200;
285*a2c472e7SAleksandr Rybalko 		break;
286*a2c472e7SAleksandr Rybalko 	default:
287*a2c472e7SAleksandr Rybalko 		error = EINVAL;
288*a2c472e7SAleksandr Rybalko 		break;
289*a2c472e7SAleksandr Rybalko 	}
290*a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
291*a2c472e7SAleksandr Rybalko 
292*a2c472e7SAleksandr Rybalko 	return (error);
293*a2c472e7SAleksandr Rybalko }
294*a2c472e7SAleksandr Rybalko 
295*a2c472e7SAleksandr Rybalko static int
296*a2c472e7SAleksandr Rybalko imx_uart_bus_ipend(struct uart_softc *sc)
297*a2c472e7SAleksandr Rybalko {
298*a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
299*a2c472e7SAleksandr Rybalko 	int ipend;
300*a2c472e7SAleksandr Rybalko 	uint32_t usr1, usr2;
301*a2c472e7SAleksandr Rybalko 	uint32_t ucr1, ucr4;
302*a2c472e7SAleksandr Rybalko 
303*a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
304*a2c472e7SAleksandr Rybalko 	ipend = 0;
305*a2c472e7SAleksandr Rybalko 
306*a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
307*a2c472e7SAleksandr Rybalko 
308*a2c472e7SAleksandr Rybalko 	/* Read pending interrupts */
309*a2c472e7SAleksandr Rybalko 	usr1 = GETREG(bas, REG(USR1));
310*a2c472e7SAleksandr Rybalko 	usr2 = GETREG(bas, REG(USR2));
311*a2c472e7SAleksandr Rybalko 	/* ACK interrupts */
312*a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR1), usr1);
313*a2c472e7SAleksandr Rybalko 	SETREG(bas, REG(USR2), usr2);
314*a2c472e7SAleksandr Rybalko 
315*a2c472e7SAleksandr Rybalko 	ucr1 = GETREG(bas, REG(UCR1));
316*a2c472e7SAleksandr Rybalko 	ucr4 = GETREG(bas, REG(UCR4));
317*a2c472e7SAleksandr Rybalko 
318*a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, TXFE)) && (ucr1 & FLD(UCR1, TXMPTYEN))) {
319*a2c472e7SAleksandr Rybalko 		DIS(bas, UCR1, TXMPTYEN);
320*a2c472e7SAleksandr Rybalko 		/* Continue TXing */
321*a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_TXIDLE;
322*a2c472e7SAleksandr Rybalko 	}
323*a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, RDR)) && (ucr4 & FLD(UCR4, DREN))) {
324*a2c472e7SAleksandr Rybalko 		DIS(bas, UCR4, DREN);
325*a2c472e7SAleksandr Rybalko 		/* Wow, new char on input */
326*a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_RXREADY;
327*a2c472e7SAleksandr Rybalko 	}
328*a2c472e7SAleksandr Rybalko 	if ((usr2 & FLD(USR2, BRCD)) && (ucr4 & FLD(UCR4, BKEN)))
329*a2c472e7SAleksandr Rybalko 		ipend |= SER_INT_BREAK;
330*a2c472e7SAleksandr Rybalko 
331*a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
332*a2c472e7SAleksandr Rybalko 
333*a2c472e7SAleksandr Rybalko 	return (ipend);
334*a2c472e7SAleksandr Rybalko }
335*a2c472e7SAleksandr Rybalko 
336*a2c472e7SAleksandr Rybalko static int
337*a2c472e7SAleksandr Rybalko imx_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
338*a2c472e7SAleksandr Rybalko     int stopbits, int parity)
339*a2c472e7SAleksandr Rybalko {
340*a2c472e7SAleksandr Rybalko 
341*a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
342*a2c472e7SAleksandr Rybalko 	imx_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
343*a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
344*a2c472e7SAleksandr Rybalko 	return (0);
345*a2c472e7SAleksandr Rybalko }
346*a2c472e7SAleksandr Rybalko 
347*a2c472e7SAleksandr Rybalko static int
348*a2c472e7SAleksandr Rybalko imx_uart_bus_probe(struct uart_softc *sc)
349*a2c472e7SAleksandr Rybalko {
350*a2c472e7SAleksandr Rybalko 	int error;
351*a2c472e7SAleksandr Rybalko 
352*a2c472e7SAleksandr Rybalko 	error = imx_uart_probe(&sc->sc_bas);
353*a2c472e7SAleksandr Rybalko 	if (error)
354*a2c472e7SAleksandr Rybalko 		return (error);
355*a2c472e7SAleksandr Rybalko 
356*a2c472e7SAleksandr Rybalko 	device_set_desc(sc->sc_dev, "imx_uart");
357*a2c472e7SAleksandr Rybalko 	return (0);
358*a2c472e7SAleksandr Rybalko }
359*a2c472e7SAleksandr Rybalko 
360*a2c472e7SAleksandr Rybalko static int
361*a2c472e7SAleksandr Rybalko imx_uart_bus_receive(struct uart_softc *sc)
362*a2c472e7SAleksandr Rybalko {
363*a2c472e7SAleksandr Rybalko 	struct uart_bas *bas;
364*a2c472e7SAleksandr Rybalko 	int xc, out;
365*a2c472e7SAleksandr Rybalko 
366*a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
367*a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
368*a2c472e7SAleksandr Rybalko 
369*a2c472e7SAleksandr Rybalko 	/* Read while we have anything in FIFO */
370*a2c472e7SAleksandr Rybalko 	while (IS(bas, USR2, RDR)) {
371*a2c472e7SAleksandr Rybalko 		if (uart_rx_full(sc)) {
372*a2c472e7SAleksandr Rybalko 			/* No space left in input buffer */
373*a2c472e7SAleksandr Rybalko 			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
374*a2c472e7SAleksandr Rybalko 			break;
375*a2c472e7SAleksandr Rybalko 		}
376*a2c472e7SAleksandr Rybalko 		out = 0;
377*a2c472e7SAleksandr Rybalko 		xc = GETREG(bas, REG(URXD));
378*a2c472e7SAleksandr Rybalko 
379*a2c472e7SAleksandr Rybalko 		/* We have valid char */
380*a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, CHARRDY))
381*a2c472e7SAleksandr Rybalko 			out = xc & 0x000000ff;
382*a2c472e7SAleksandr Rybalko 
383*a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, FRMERR))
384*a2c472e7SAleksandr Rybalko 			out |= UART_STAT_FRAMERR;
385*a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, PRERR))
386*a2c472e7SAleksandr Rybalko 			out |= UART_STAT_PARERR;
387*a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, OVRRUN))
388*a2c472e7SAleksandr Rybalko 			out |= UART_STAT_OVERRUN;
389*a2c472e7SAleksandr Rybalko 		if (xc & FLD(URXD, BRK))
390*a2c472e7SAleksandr Rybalko 			out |= UART_STAT_BREAK;
391*a2c472e7SAleksandr Rybalko 
392*a2c472e7SAleksandr Rybalko 		uart_rx_put(sc, out);
393*a2c472e7SAleksandr Rybalko 	}
394*a2c472e7SAleksandr Rybalko 	/* Reenable Data Ready interrupt */
395*a2c472e7SAleksandr Rybalko 	ENA(bas, UCR4, DREN);
396*a2c472e7SAleksandr Rybalko 
397*a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
398*a2c472e7SAleksandr Rybalko 	return (0);
399*a2c472e7SAleksandr Rybalko }
400*a2c472e7SAleksandr Rybalko 
401*a2c472e7SAleksandr Rybalko static int
402*a2c472e7SAleksandr Rybalko imx_uart_bus_setsig(struct uart_softc *sc, int sig)
403*a2c472e7SAleksandr Rybalko {
404*a2c472e7SAleksandr Rybalko 
405*a2c472e7SAleksandr Rybalko 	/* TODO: implement (?) */
406*a2c472e7SAleksandr Rybalko 
407*a2c472e7SAleksandr Rybalko 	/* XXX workaround to have working console on mount prompt */
408*a2c472e7SAleksandr Rybalko 	/* Enable RX interrupt */
409*a2c472e7SAleksandr Rybalko 	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE)
410*a2c472e7SAleksandr Rybalko 		if (!IS(&sc->sc_bas, UCR4, DREN))
411*a2c472e7SAleksandr Rybalko 			ENA(&sc->sc_bas, UCR4, DREN);
412*a2c472e7SAleksandr Rybalko 	return (0);
413*a2c472e7SAleksandr Rybalko }
414*a2c472e7SAleksandr Rybalko 
415*a2c472e7SAleksandr Rybalko static int
416*a2c472e7SAleksandr Rybalko imx_uart_bus_transmit(struct uart_softc *sc)
417*a2c472e7SAleksandr Rybalko {
418*a2c472e7SAleksandr Rybalko 	struct uart_bas *bas = &sc->sc_bas;
419*a2c472e7SAleksandr Rybalko 	int i;
420*a2c472e7SAleksandr Rybalko 
421*a2c472e7SAleksandr Rybalko 	bas = &sc->sc_bas;
422*a2c472e7SAleksandr Rybalko 	uart_lock(sc->sc_hwmtx);
423*a2c472e7SAleksandr Rybalko 
424*a2c472e7SAleksandr Rybalko 	/* Fill TX FIFO */
425*a2c472e7SAleksandr Rybalko 	for (i = 0; i < sc->sc_txdatasz; i++) {
426*a2c472e7SAleksandr Rybalko 		SETREG(bas, REG(UTXD), sc->sc_txbuf[i] & 0xff);
427*a2c472e7SAleksandr Rybalko 	}
428*a2c472e7SAleksandr Rybalko 
429*a2c472e7SAleksandr Rybalko 	sc->sc_txbusy = 1;
430*a2c472e7SAleksandr Rybalko 	/* Call me when ready */
431*a2c472e7SAleksandr Rybalko 	ENA(bas, UCR1, TXMPTYEN);
432*a2c472e7SAleksandr Rybalko 
433*a2c472e7SAleksandr Rybalko 	uart_unlock(sc->sc_hwmtx);
434*a2c472e7SAleksandr Rybalko 
435*a2c472e7SAleksandr Rybalko 	return (0);
436*a2c472e7SAleksandr Rybalko }
437