1297669Ssgalabov/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
2297669Ssgalabov
3297669Ssgalabov/*-
4297669Ssgalabov * Copyright (c) 2013, Alexander A. Mityaev <sansan@adm.ua>
5297669Ssgalabov * Copyright (c) 2010 Aleksandr Rybalko.
6297669Ssgalabov * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
7297669Ssgalabov * Copyright (c) 2007 Oleksandr Tymoshenko.
8297669Ssgalabov * All rights reserved.
9297669Ssgalabov *
10297669Ssgalabov * Redistribution and use in source and binary forms, with or
11297669Ssgalabov * without modification, are permitted provided that the following
12297669Ssgalabov * conditions are met:
13297669Ssgalabov * 1. Redistributions of source code must retain the above copyright
14297669Ssgalabov *    notice, this list of conditions and the following disclaimer.
15297669Ssgalabov * 2. Redistributions in binary form must reproduce the above
16297669Ssgalabov *    copyright notice, this list of conditions and the following
17297669Ssgalabov *    disclaimer in the documentation and/or other materials provided
18297669Ssgalabov *    with the distribution.
19297669Ssgalabov *
20297669Ssgalabov * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
21297669Ssgalabov * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22297669Ssgalabov * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23297669Ssgalabov * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS
24297669Ssgalabov * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25297669Ssgalabov * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26297669Ssgalabov * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27297669Ssgalabov * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28297669Ssgalabov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29297669Ssgalabov * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30297669Ssgalabov * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31297669Ssgalabov * OF SUCH DAMAGE.
32297669Ssgalabov */
33297669Ssgalabov
34297669Ssgalabov#include <sys/cdefs.h>
35297669Ssgalabov__FBSDID("$FreeBSD$");
36297669Ssgalabov
37297669Ssgalabov#include "opt_ddb.h"
38297669Ssgalabov
39297669Ssgalabov#include <sys/param.h>
40297669Ssgalabov#include <sys/systm.h>
41297669Ssgalabov#include <sys/bus.h>
42297669Ssgalabov#include <sys/conf.h>
43297669Ssgalabov#include <sys/kdb.h>
44297669Ssgalabov#include <sys/reboot.h>
45297669Ssgalabov#include <sys/sysctl.h>
46297669Ssgalabov#include <sys/kernel.h>
47297669Ssgalabov#include <machine/bus.h>
48297669Ssgalabov#include <machine/fdt.h>
49297669Ssgalabov
50297669Ssgalabov#include <dev/uart/uart.h>
51297669Ssgalabov#include <dev/uart/uart_cpu.h>
52297669Ssgalabov#include <dev/uart/uart_cpu_fdt.h>
53297669Ssgalabov#include <dev/uart/uart_bus.h>
54297669Ssgalabov
55297669Ssgalabov#include <mips/mediatek/uart_dev_mtk.h>
56297669Ssgalabov#include <mips/mediatek/mtk_soc.h>
57297669Ssgalabov#include <mips/mediatek/mtk_sysctl.h>
58297669Ssgalabov
59297669Ssgalabov#include "uart_if.h"
60297669Ssgalabov
61297669Ssgalabov/* Set some reference clock value. Real value will be taken from FDT */
62297669Ssgalabov#define DEFAULT_RCLK            (120 * 1000 * 1000)
63297669Ssgalabov
64297669Ssgalabov/*
65297669Ssgalabov * Low-level UART interface.
66297669Ssgalabov */
67297669Ssgalabovstatic int mtk_uart_probe(struct uart_bas *bas);
68297669Ssgalabovstatic void mtk_uart_init(struct uart_bas *bas, int, int, int, int);
69297669Ssgalabovstatic void mtk_uart_term(struct uart_bas *bas);
70297669Ssgalabovstatic void mtk_uart_putc(struct uart_bas *bas, int);
71297669Ssgalabovstatic int mtk_uart_rxready(struct uart_bas *bas);
72297669Ssgalabovstatic int mtk_uart_getc(struct uart_bas *bas, struct mtx *);
73297669Ssgalabov
74297669Ssgalabovstatic struct uart_ops uart_mtk_ops = {
75297669Ssgalabov	.probe = mtk_uart_probe,
76297669Ssgalabov	.init = mtk_uart_init,
77297669Ssgalabov	.term = mtk_uart_term,
78297669Ssgalabov	.putc = mtk_uart_putc,
79297669Ssgalabov	.rxready = mtk_uart_rxready,
80297669Ssgalabov	.getc = mtk_uart_getc,
81297669Ssgalabov};
82297669Ssgalabov
83297669Ssgalabovstatic int	uart_output = 1;
84297669SsgalabovTUNABLE_INT("kern.uart_output", &uart_output);
85297669SsgalabovSYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW,
86297669Ssgalabov    &uart_output, 0, "UART output enabled.");
87297669Ssgalabov
88297669Ssgalabovstatic int
89297669Ssgalabovmtk_uart_probe(struct uart_bas *bas)
90297669Ssgalabov{
91297669Ssgalabov	return (0);
92297669Ssgalabov}
93297669Ssgalabov
94297669Ssgalabovstatic void
95297669Ssgalabovmtk_uart_init(struct uart_bas *bas, int baudrate, int databits,
96297669Ssgalabov    int stopbits, int parity)
97297669Ssgalabov{
98297669Ssgalabov        /* CLKDIV  = 384000000/ 3/ 16/ br */
99297669Ssgalabov        /* for 384MHz CLKDIV = 8000000 / baudrate; */
100297669Ssgalabov        switch (databits) {
101297669Ssgalabov        case 5:
102297669Ssgalabov    		databits = UART_LCR_5B;
103297669Ssgalabov    		break;
104297669Ssgalabov        case 6:
105297669Ssgalabov    		databits = UART_LCR_6B;
106297669Ssgalabov    		break;
107297669Ssgalabov        case 7:
108297669Ssgalabov    		databits = UART_LCR_7B;
109297669Ssgalabov    		break;
110297669Ssgalabov        case 8:
111297669Ssgalabov    		databits = UART_LCR_8B;
112297669Ssgalabov    		break;
113297669Ssgalabov    	default:
114297669Ssgalabov    		/* Unsupported */
115297669Ssgalabov    		return;
116297669Ssgalabov        }
117297669Ssgalabov	switch (parity) {
118297669Ssgalabov	case UART_PARITY_EVEN:	parity = (UART_LCR_PEN|UART_LCR_EVEN); break;
119297669Ssgalabov	case UART_PARITY_ODD:	parity = (UART_LCR_PEN); break;
120297669Ssgalabov	case UART_PARITY_NONE:	parity = 0; break;
121297669Ssgalabov	/* Unsupported */
122297669Ssgalabov	default:		return;
123297669Ssgalabov	}
124297669Ssgalabov
125297669Ssgalabov	if (bas->rclk && baudrate) {
126297669Ssgalabov        	uart_setreg(bas, UART_CDDL_REG, bas->rclk/16/baudrate);
127297669Ssgalabov		uart_barrier(bas);
128297669Ssgalabov	}
129297669Ssgalabov
130297669Ssgalabov        uart_setreg(bas, UART_LCR_REG, databits |
131297669Ssgalabov				(stopbits==1?0:UART_LCR_STB_15) |
132297669Ssgalabov       			 	parity);
133297669Ssgalabov	uart_barrier(bas);
134297669Ssgalabov}
135297669Ssgalabov
136297669Ssgalabovstatic void
137297669Ssgalabovmtk_uart_term(struct uart_bas *bas)
138297669Ssgalabov{
139297669Ssgalabov        uart_setreg(bas, UART_MCR_REG, 0);
140297669Ssgalabov	uart_barrier(bas);
141297669Ssgalabov}
142297669Ssgalabov
143297669Ssgalabovstatic void
144297669Ssgalabovmtk_uart_putc(struct uart_bas *bas, int c)
145297669Ssgalabov{
146297669Ssgalabov	char chr;
147297669Ssgalabov	if (!uart_output) return;
148297669Ssgalabov	chr = c;
149297669Ssgalabov	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
150297669Ssgalabov	uart_setreg(bas, UART_TX_REG, c);
151297669Ssgalabov	uart_barrier(bas);
152297669Ssgalabov	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
153297669Ssgalabov}
154297669Ssgalabov
155297669Ssgalabovstatic int
156297669Ssgalabovmtk_uart_rxready(struct uart_bas *bas)
157297669Ssgalabov{
158297669Ssgalabov	if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)
159297669Ssgalabov		return (1);
160297669Ssgalabov	return (0);
161297669Ssgalabov}
162297669Ssgalabov
163297669Ssgalabovstatic int
164297669Ssgalabovmtk_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
165297669Ssgalabov{
166297669Ssgalabov	int c;
167297669Ssgalabov
168297669Ssgalabov	uart_lock(hwmtx);
169297669Ssgalabov
170297669Ssgalabov	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) {
171297669Ssgalabov		uart_unlock(hwmtx);
172297669Ssgalabov		DELAY(10);
173297669Ssgalabov		uart_lock(hwmtx);
174297669Ssgalabov	}
175297669Ssgalabov
176297669Ssgalabov	c = uart_getreg(bas, UART_RX_REG);
177297669Ssgalabov
178297669Ssgalabov	uart_unlock(hwmtx);
179297669Ssgalabov
180297669Ssgalabov	return (c);
181297669Ssgalabov}
182297669Ssgalabov
183297669Ssgalabov/*
184297669Ssgalabov * High-level UART interface.
185297669Ssgalabov */
186297669Ssgalabovstruct uart_mtk_softc {
187297669Ssgalabov	struct uart_softc base;
188297669Ssgalabov	uint8_t ier_mask;
189297669Ssgalabov	uint8_t ier;
190297669Ssgalabov};
191297669Ssgalabov
192297669Ssgalabovstatic int mtk_uart_bus_attach(struct uart_softc *);
193297669Ssgalabovstatic int mtk_uart_bus_detach(struct uart_softc *);
194297669Ssgalabovstatic int mtk_uart_bus_flush(struct uart_softc *, int);
195297669Ssgalabovstatic int mtk_uart_bus_getsig(struct uart_softc *);
196297669Ssgalabovstatic int mtk_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
197297669Ssgalabovstatic int mtk_uart_bus_ipend(struct uart_softc *);
198297669Ssgalabovstatic int mtk_uart_bus_param(struct uart_softc *, int, int, int, int);
199297669Ssgalabovstatic int mtk_uart_bus_probe(struct uart_softc *);
200297669Ssgalabovstatic int mtk_uart_bus_receive(struct uart_softc *);
201297669Ssgalabovstatic int mtk_uart_bus_setsig(struct uart_softc *, int);
202297669Ssgalabovstatic int mtk_uart_bus_transmit(struct uart_softc *);
203297669Ssgalabovstatic void mtk_uart_bus_grab(struct uart_softc *);
204297669Ssgalabovstatic void mtk_uart_bus_ungrab(struct uart_softc *);
205297669Ssgalabov
206297669Ssgalabovstatic kobj_method_t uart_mtk_methods[] = {
207297669Ssgalabov	KOBJMETHOD(uart_attach,		mtk_uart_bus_attach),
208297669Ssgalabov	KOBJMETHOD(uart_detach,		mtk_uart_bus_detach),
209297669Ssgalabov	KOBJMETHOD(uart_flush,		mtk_uart_bus_flush),
210297669Ssgalabov	KOBJMETHOD(uart_getsig,		mtk_uart_bus_getsig),
211297669Ssgalabov	KOBJMETHOD(uart_ioctl,		mtk_uart_bus_ioctl),
212297669Ssgalabov	KOBJMETHOD(uart_ipend,		mtk_uart_bus_ipend),
213297669Ssgalabov	KOBJMETHOD(uart_param,		mtk_uart_bus_param),
214297669Ssgalabov	KOBJMETHOD(uart_probe,		mtk_uart_bus_probe),
215297669Ssgalabov	KOBJMETHOD(uart_receive,	mtk_uart_bus_receive),
216297669Ssgalabov	KOBJMETHOD(uart_setsig,		mtk_uart_bus_setsig),
217297669Ssgalabov	KOBJMETHOD(uart_transmit,	mtk_uart_bus_transmit),
218297669Ssgalabov	KOBJMETHOD(uart_grab,		mtk_uart_bus_grab),
219297669Ssgalabov	KOBJMETHOD(uart_ungrab,		mtk_uart_bus_ungrab),
220297669Ssgalabov	{ 0, 0 }
221297669Ssgalabov};
222297669Ssgalabov
223297669Ssgalabovstruct uart_class uart_mtk_class = {
224297669Ssgalabov	"uart_mtk",
225297669Ssgalabov	uart_mtk_methods,
226297669Ssgalabov	sizeof(struct uart_mtk_softc),
227297669Ssgalabov	.uc_ops = &uart_mtk_ops,
228297669Ssgalabov	.uc_range = 1, /* use hinted range */
229297669Ssgalabov	.uc_rclk = 0
230297669Ssgalabov};
231297669Ssgalabov
232297669Ssgalabovstatic struct ofw_compat_data compat_data[] = {
233297669Ssgalabov	{ "ralink,rt2880-uart",		(uintptr_t)&uart_mtk_class },
234297669Ssgalabov	{ "ralink,rt3050-uart",		(uintptr_t)&uart_mtk_class },
235297669Ssgalabov	{ "ralink,rt3352-uart",		(uintptr_t)&uart_mtk_class },
236297669Ssgalabov	{ "ralink,rt3883-uart",		(uintptr_t)&uart_mtk_class },
237297669Ssgalabov	{ "ralink,rt5350-uart",		(uintptr_t)&uart_mtk_class },
238297669Ssgalabov	{ "ralink,mt7620a-uart",	(uintptr_t)&uart_mtk_class },
239297669Ssgalabov	{ NULL,				(uintptr_t)NULL },
240297669Ssgalabov};
241297669SsgalabovUART_FDT_CLASS_AND_DEVICE(compat_data);
242297669Ssgalabov
243297669Ssgalabov
244297669Ssgalabov#define	SIGCHG(c, i, s, d)				\
245297669Ssgalabov	if (c) {					\
246297669Ssgalabov		i |= (i & s) ? s : s | d;		\
247297669Ssgalabov	} else {					\
248297669Ssgalabov		i = (i & s) ? (i & ~s) | d : i;		\
249297669Ssgalabov	}
250297669Ssgalabov
251297669Ssgalabov/*
252297669Ssgalabov * Disable TX interrupt. uart should be locked
253297669Ssgalabov */
254297669Ssgalabovstatic __inline void
255297669Ssgalabovmtk_uart_disable_txintr(struct uart_softc *sc)
256297669Ssgalabov{
257297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
258297669Ssgalabov	uint8_t cr;
259297669Ssgalabov
260297669Ssgalabov	cr = uart_getreg(bas, UART_IER_REG);
261297669Ssgalabov	cr &= ~UART_IER_ETBEI;
262297669Ssgalabov	uart_setreg(bas, UART_IER_REG, cr);
263297669Ssgalabov	uart_barrier(bas);
264297669Ssgalabov}
265297669Ssgalabov
266297669Ssgalabov/*
267297669Ssgalabov * Enable TX interrupt. uart should be locked
268297669Ssgalabov */
269297669Ssgalabovstatic __inline void
270297669Ssgalabovmtk_uart_enable_txintr(struct uart_softc *sc)
271297669Ssgalabov{
272297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
273297669Ssgalabov	uint8_t cr;
274297669Ssgalabov
275297669Ssgalabov	cr = uart_getreg(bas, UART_IER_REG);
276297669Ssgalabov	cr |= UART_IER_ETBEI;
277297669Ssgalabov	uart_setreg(bas, UART_IER_REG, cr);
278297669Ssgalabov	uart_barrier(bas);
279297669Ssgalabov}
280297669Ssgalabov
281297669Ssgalabovstatic int
282297669Ssgalabovmtk_uart_bus_attach(struct uart_softc *sc)
283297669Ssgalabov{
284297669Ssgalabov	struct uart_bas *bas;
285297669Ssgalabov	struct uart_devinfo *di;
286297669Ssgalabov	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
287297669Ssgalabov
288297669Ssgalabov	bas = &sc->sc_bas;
289297669Ssgalabov
290297669Ssgalabov	if (!bas->rclk) {
291297669Ssgalabov		bas->rclk = mtk_soc_get_uartclk();
292297669Ssgalabov	}
293297669Ssgalabov
294297669Ssgalabov	if (sc->sc_sysdev != NULL) {
295297669Ssgalabov		di = sc->sc_sysdev;
296297669Ssgalabov		mtk_uart_init(bas, di->baudrate, di->databits, di->stopbits,
297297669Ssgalabov		    di->parity);
298297669Ssgalabov	} else {
299297669Ssgalabov		mtk_uart_init(bas, 57600, 8, 1, 0);
300297669Ssgalabov	}
301297669Ssgalabov
302297669Ssgalabov	sc->sc_rxfifosz = 16;
303297669Ssgalabov	sc->sc_txfifosz = 16;
304297669Ssgalabov
305297669Ssgalabov	(void)mtk_uart_bus_getsig(sc);
306297669Ssgalabov
307297669Ssgalabov	/* Enable FIFO */
308297669Ssgalabov	uart_setreg(bas, UART_FCR_REG,
309297669Ssgalabov	    uart_getreg(bas, UART_FCR_REG) |
310297669Ssgalabov	    UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1);
311297669Ssgalabov	uart_barrier(bas);
312297669Ssgalabov	/* Enable interrupts */
313297669Ssgalabov	usc->ier_mask = 0xf0;
314297669Ssgalabov	uart_setreg(bas, UART_IER_REG,
315297669Ssgalabov	    UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI);
316297669Ssgalabov	uart_barrier(bas);
317297669Ssgalabov
318297669Ssgalabov	return (0);
319297669Ssgalabov}
320297669Ssgalabov
321297669Ssgalabovstatic int
322297669Ssgalabovmtk_uart_bus_detach(struct uart_softc *sc)
323297669Ssgalabov{
324297669Ssgalabov	return (0);
325297669Ssgalabov}
326297669Ssgalabov
327297669Ssgalabovstatic int
328297669Ssgalabovmtk_uart_bus_flush(struct uart_softc *sc, int what)
329297669Ssgalabov{
330297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
331297669Ssgalabov	uint32_t fcr = uart_getreg(bas, UART_FCR_REG);
332297669Ssgalabov
333297669Ssgalabov	if (what & UART_FLUSH_TRANSMITTER) {
334297669Ssgalabov		uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST);
335297669Ssgalabov		uart_barrier(bas);
336297669Ssgalabov	}
337297669Ssgalabov	if (what & UART_FLUSH_RECEIVER) {
338297669Ssgalabov		uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST);
339297669Ssgalabov		uart_barrier(bas);
340297669Ssgalabov	}
341297669Ssgalabov	uart_setreg(bas, UART_FCR_REG, fcr);
342297669Ssgalabov	uart_barrier(bas);
343297669Ssgalabov	return (0);
344297669Ssgalabov}
345297669Ssgalabov
346297669Ssgalabovstatic int
347297669Ssgalabovmtk_uart_bus_getsig(struct uart_softc *sc)
348297669Ssgalabov{
349297669Ssgalabov	uint32_t new, old, sig;
350297669Ssgalabov	uint8_t bes;
351297669Ssgalabov
352297669Ssgalabov	return(0);
353297669Ssgalabov	do {
354297669Ssgalabov		old = sc->sc_hwsig;
355297669Ssgalabov		sig = old;
356297669Ssgalabov		uart_lock(sc->sc_hwmtx);
357297669Ssgalabov		bes = uart_getreg(&sc->sc_bas, UART_MSR_REG);
358297669Ssgalabov		uart_unlock(sc->sc_hwmtx);
359297669Ssgalabov		/* XXX: chip can show delta */
360297669Ssgalabov		SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS);
361297669Ssgalabov		SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD);
362297669Ssgalabov		SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR);
363297669Ssgalabov		new = sig & ~SER_MASK_DELTA;
364297669Ssgalabov	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
365297669Ssgalabov
366297669Ssgalabov	return (sig);
367297669Ssgalabov}
368297669Ssgalabov
369297669Ssgalabovstatic int
370297669Ssgalabovmtk_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
371297669Ssgalabov{
372297669Ssgalabov	struct uart_bas *bas;
373297669Ssgalabov	int baudrate, divisor, error;
374297669Ssgalabov
375297669Ssgalabov	bas = &sc->sc_bas;
376297669Ssgalabov	error = 0;
377297669Ssgalabov	uart_lock(sc->sc_hwmtx);
378297669Ssgalabov	switch (request) {
379297669Ssgalabov	case UART_IOCTL_BREAK:
380297669Ssgalabov		/* TODO: Send BREAK */
381297669Ssgalabov		break;
382297669Ssgalabov	case UART_IOCTL_BAUD:
383297669Ssgalabov		divisor = uart_getreg(bas, UART_CDDL_REG);
384297669Ssgalabov		baudrate = bas->rclk / (divisor * 16);
385297669Ssgalabov		*(int*)data = baudrate;
386297669Ssgalabov		break;
387297669Ssgalabov	default:
388297669Ssgalabov		error = EINVAL;
389297669Ssgalabov		break;
390297669Ssgalabov	}
391297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
392297669Ssgalabov	return (error);
393297669Ssgalabov}
394297669Ssgalabov
395297669Ssgalabovstatic int
396297669Ssgalabovmtk_uart_bus_ipend(struct uart_softc *sc)
397297669Ssgalabov{
398297669Ssgalabov	struct uart_bas *bas;
399297669Ssgalabov	int ipend;
400297669Ssgalabov	uint8_t iir, lsr, msr;
401297669Ssgalabov
402297669Ssgalabov//	breakpoint();
403297669Ssgalabov
404297669Ssgalabov	bas = &sc->sc_bas;
405297669Ssgalabov	ipend = 0;
406297669Ssgalabov
407297669Ssgalabov	uart_lock(sc->sc_hwmtx);
408297669Ssgalabov	iir = uart_getreg(&sc->sc_bas, UART_IIR_REG);
409297669Ssgalabov	lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG);
410297669Ssgalabov	uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr);
411297669Ssgalabov	msr = uart_getreg(&sc->sc_bas, UART_MSR_REG);
412297669Ssgalabov	uart_setreg(&sc->sc_bas, UART_MSR_REG, msr);
413297669Ssgalabov	if (iir & UART_IIR_INTP) {
414297669Ssgalabov		uart_unlock(sc->sc_hwmtx);
415297669Ssgalabov		return (0);
416297669Ssgalabov	}
417297669Ssgalabov	switch ((iir >> 1) & 0x07) {
418297669Ssgalabov	case UART_IIR_ID_THRE:
419297669Ssgalabov		ipend |= SER_INT_TXIDLE;
420297669Ssgalabov		break;
421297669Ssgalabov	case UART_IIR_ID_DR2:
422297669Ssgalabov		mtk_uart_bus_flush(sc, UART_FLUSH_RECEIVER);
423297669Ssgalabov		/* passthrough */
424297669Ssgalabov	case UART_IIR_ID_DR:
425297669Ssgalabov		ipend |= SER_INT_RXREADY;
426297669Ssgalabov		break;
427297669Ssgalabov	case UART_IIR_ID_MST:
428297669Ssgalabov	case UART_IIR_ID_LINESTATUS:
429297669Ssgalabov		ipend |= SER_INT_SIGCHG;
430297669Ssgalabov		if (lsr & UART_LSR_BI)
431297669Ssgalabov			ipend |= SER_INT_BREAK;
432297669Ssgalabov		if (lsr & UART_LSR_OE)
433297669Ssgalabov			ipend |= SER_INT_OVERRUN;
434297669Ssgalabov		break;
435297669Ssgalabov	default:
436297669Ssgalabov		/* XXX: maybe return error here */
437297669Ssgalabov		break;
438297669Ssgalabov	}
439297669Ssgalabov
440297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
441297669Ssgalabov
442297669Ssgalabov	return (ipend);
443297669Ssgalabov}
444297669Ssgalabov
445297669Ssgalabovstatic int
446297669Ssgalabovmtk_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
447297669Ssgalabov    int stopbits, int parity)
448297669Ssgalabov{
449297669Ssgalabov	uart_lock(sc->sc_hwmtx);
450297669Ssgalabov	mtk_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
451297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
452297669Ssgalabov	return (0);
453297669Ssgalabov}
454297669Ssgalabov
455297669Ssgalabovstatic int
456297669Ssgalabovmtk_uart_bus_probe(struct uart_softc *sc)
457297669Ssgalabov{
458297669Ssgalabov	int error;
459297669Ssgalabov
460297669Ssgalabov	error = mtk_uart_probe(&sc->sc_bas);
461297669Ssgalabov	if (error)
462297669Ssgalabov		return (error);
463297669Ssgalabov
464297669Ssgalabov	device_set_desc(sc->sc_dev, "MTK UART Controller");
465297669Ssgalabov
466297669Ssgalabov	return (0);
467297669Ssgalabov}
468297669Ssgalabov
469297669Ssgalabovstatic int
470297669Ssgalabovmtk_uart_bus_receive(struct uart_softc *sc)
471297669Ssgalabov{
472297669Ssgalabov	struct uart_bas *bas;
473297669Ssgalabov	int xc;
474297669Ssgalabov	uint8_t lsr;
475297669Ssgalabov
476297669Ssgalabov	bas = &sc->sc_bas;
477297669Ssgalabov	uart_lock(sc->sc_hwmtx);
478297669Ssgalabov	lsr = uart_getreg(bas, UART_LSR_REG);
479297669Ssgalabov	while ((lsr & UART_LSR_DR)) {
480297669Ssgalabov		if (uart_rx_full(sc)) {
481297669Ssgalabov			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
482297669Ssgalabov			break;
483297669Ssgalabov		}
484297669Ssgalabov		xc = 0;
485297669Ssgalabov		xc = uart_getreg(bas, UART_RX_REG);
486297669Ssgalabov		if (lsr & UART_LSR_FE)
487297669Ssgalabov			xc |= UART_STAT_FRAMERR;
488297669Ssgalabov		if (lsr & UART_LSR_PE)
489297669Ssgalabov			xc |= UART_STAT_PARERR;
490297669Ssgalabov		if (lsr & UART_LSR_OE)
491297669Ssgalabov			xc |= UART_STAT_OVERRUN;
492297669Ssgalabov		uart_barrier(bas);
493297669Ssgalabov		uart_rx_put(sc, xc);
494297669Ssgalabov		lsr = uart_getreg(bas, UART_LSR_REG);
495297669Ssgalabov	}
496297669Ssgalabov
497297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
498297669Ssgalabov	return (0);
499297669Ssgalabov}
500297669Ssgalabov
501297669Ssgalabovstatic int
502297669Ssgalabovmtk_uart_bus_setsig(struct uart_softc *sc, int sig)
503297669Ssgalabov{
504297669Ssgalabov	/* TODO: implement (?) */
505297669Ssgalabov	return (sig);
506297669Ssgalabov}
507297669Ssgalabov
508297669Ssgalabovstatic int
509297669Ssgalabovmtk_uart_bus_transmit(struct uart_softc *sc)
510297669Ssgalabov{
511297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
512297669Ssgalabov	int i;
513297669Ssgalabov
514297669Ssgalabov	if (!uart_output) return (0);
515297669Ssgalabov
516297669Ssgalabov	bas = &sc->sc_bas;
517297669Ssgalabov	uart_lock(sc->sc_hwmtx);
518297669Ssgalabov	while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0);
519297669Ssgalabov	mtk_uart_enable_txintr(sc);
520297669Ssgalabov	for (i = 0; i < sc->sc_txdatasz; i++) {
521297669Ssgalabov		uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]);
522297669Ssgalabov		uart_barrier(bas);
523297669Ssgalabov	}
524297669Ssgalabov	sc->sc_txbusy = 1;
525297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
526297669Ssgalabov	return (0);
527297669Ssgalabov}
528297669Ssgalabov
529297669Ssgalabovvoid
530297669Ssgalabovmtk_uart_bus_grab(struct uart_softc *sc)
531297669Ssgalabov{
532297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
533297669Ssgalabov	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
534297669Ssgalabov
535297669Ssgalabov	uart_lock(sc->sc_hwmtx);
536297669Ssgalabov	usc->ier = uart_getreg(bas, UART_IER_REG);
537297669Ssgalabov	uart_setreg(bas, UART_IER_REG, usc->ier & usc->ier_mask);
538297669Ssgalabov	uart_barrier(bas);
539297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
540297669Ssgalabov}
541297669Ssgalabov
542297669Ssgalabovvoid
543297669Ssgalabovmtk_uart_bus_ungrab(struct uart_softc *sc)
544297669Ssgalabov{
545297669Ssgalabov	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
546297669Ssgalabov	struct uart_bas *bas = &sc->sc_bas;
547297669Ssgalabov
548297669Ssgalabov	uart_lock(sc->sc_hwmtx);
549297669Ssgalabov	uart_setreg(bas, UART_IER_REG, usc->ier);
550297669Ssgalabov	uart_barrier(bas);
551297669Ssgalabov	uart_unlock(sc->sc_hwmtx);
552297669Ssgalabov}
553