1*a9643ea8Slogwang /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
2*a9643ea8Slogwang 
3*a9643ea8Slogwang /*-
4*a9643ea8Slogwang  * Copyright (c) 2013, Alexander A. Mityaev <[email protected]>
5*a9643ea8Slogwang  * Copyright (c) 2010 Aleksandr Rybalko.
6*a9643ea8Slogwang  * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
7*a9643ea8Slogwang  * Copyright (c) 2007 Oleksandr Tymoshenko.
8*a9643ea8Slogwang  * All rights reserved.
9*a9643ea8Slogwang  *
10*a9643ea8Slogwang  * Redistribution and use in source and binary forms, with or
11*a9643ea8Slogwang  * without modification, are permitted provided that the following
12*a9643ea8Slogwang  * conditions are met:
13*a9643ea8Slogwang  * 1. Redistributions of source code must retain the above copyright
14*a9643ea8Slogwang  *    notice, this list of conditions and the following disclaimer.
15*a9643ea8Slogwang  * 2. Redistributions in binary form must reproduce the above
16*a9643ea8Slogwang  *    copyright notice, this list of conditions and the following
17*a9643ea8Slogwang  *    disclaimer in the documentation and/or other materials provided
18*a9643ea8Slogwang  *    with the distribution.
19*a9643ea8Slogwang  *
20*a9643ea8Slogwang  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY
21*a9643ea8Slogwang  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22*a9643ea8Slogwang  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23*a9643ea8Slogwang  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS
24*a9643ea8Slogwang  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
25*a9643ea8Slogwang  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26*a9643ea8Slogwang  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
27*a9643ea8Slogwang  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*a9643ea8Slogwang  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
29*a9643ea8Slogwang  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30*a9643ea8Slogwang  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31*a9643ea8Slogwang  * OF SUCH DAMAGE.
32*a9643ea8Slogwang  */
33*a9643ea8Slogwang 
34*a9643ea8Slogwang #include <sys/cdefs.h>
35*a9643ea8Slogwang __FBSDID("$FreeBSD$");
36*a9643ea8Slogwang 
37*a9643ea8Slogwang #include "opt_ddb.h"
38*a9643ea8Slogwang 
39*a9643ea8Slogwang #include <sys/param.h>
40*a9643ea8Slogwang #include <sys/systm.h>
41*a9643ea8Slogwang #include <sys/bus.h>
42*a9643ea8Slogwang #include <sys/conf.h>
43*a9643ea8Slogwang #include <sys/kdb.h>
44*a9643ea8Slogwang #include <sys/reboot.h>
45*a9643ea8Slogwang #include <sys/sysctl.h>
46*a9643ea8Slogwang #include <sys/kernel.h>
47*a9643ea8Slogwang #include <machine/bus.h>
48*a9643ea8Slogwang #include <machine/fdt.h>
49*a9643ea8Slogwang 
50*a9643ea8Slogwang #include <dev/uart/uart.h>
51*a9643ea8Slogwang #include <dev/uart/uart_cpu.h>
52*a9643ea8Slogwang #include <dev/uart/uart_cpu_fdt.h>
53*a9643ea8Slogwang #include <dev/uart/uart_bus.h>
54*a9643ea8Slogwang 
55*a9643ea8Slogwang #include <mips/mediatek/uart_dev_mtk.h>
56*a9643ea8Slogwang #include <mips/mediatek/mtk_soc.h>
57*a9643ea8Slogwang #include <mips/mediatek/mtk_sysctl.h>
58*a9643ea8Slogwang 
59*a9643ea8Slogwang #include "uart_if.h"
60*a9643ea8Slogwang 
61*a9643ea8Slogwang /* Set some reference clock value. Real value will be taken from FDT */
62*a9643ea8Slogwang #define DEFAULT_RCLK            (120 * 1000 * 1000)
63*a9643ea8Slogwang 
64*a9643ea8Slogwang /*
65*a9643ea8Slogwang  * Low-level UART interface.
66*a9643ea8Slogwang  */
67*a9643ea8Slogwang static int mtk_uart_probe(struct uart_bas *bas);
68*a9643ea8Slogwang static void mtk_uart_init(struct uart_bas *bas, int, int, int, int);
69*a9643ea8Slogwang static void mtk_uart_term(struct uart_bas *bas);
70*a9643ea8Slogwang static void mtk_uart_putc(struct uart_bas *bas, int);
71*a9643ea8Slogwang static int mtk_uart_rxready(struct uart_bas *bas);
72*a9643ea8Slogwang static int mtk_uart_getc(struct uart_bas *bas, struct mtx *);
73*a9643ea8Slogwang 
74*a9643ea8Slogwang static struct uart_ops uart_mtk_ops = {
75*a9643ea8Slogwang 	.probe = mtk_uart_probe,
76*a9643ea8Slogwang 	.init = mtk_uart_init,
77*a9643ea8Slogwang 	.term = mtk_uart_term,
78*a9643ea8Slogwang 	.putc = mtk_uart_putc,
79*a9643ea8Slogwang 	.rxready = mtk_uart_rxready,
80*a9643ea8Slogwang 	.getc = mtk_uart_getc,
81*a9643ea8Slogwang };
82*a9643ea8Slogwang 
83*a9643ea8Slogwang static int	uart_output = 1;
84*a9643ea8Slogwang TUNABLE_INT("kern.uart_output", &uart_output);
85*a9643ea8Slogwang SYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RW,
86*a9643ea8Slogwang     &uart_output, 0, "UART output enabled.");
87*a9643ea8Slogwang 
88*a9643ea8Slogwang static int
mtk_uart_probe(struct uart_bas * bas)89*a9643ea8Slogwang mtk_uart_probe(struct uart_bas *bas)
90*a9643ea8Slogwang {
91*a9643ea8Slogwang 	return (0);
92*a9643ea8Slogwang }
93*a9643ea8Slogwang 
94*a9643ea8Slogwang static void
mtk_uart_init(struct uart_bas * bas,int baudrate,int databits,int stopbits,int parity)95*a9643ea8Slogwang mtk_uart_init(struct uart_bas *bas, int baudrate, int databits,
96*a9643ea8Slogwang     int stopbits, int parity)
97*a9643ea8Slogwang {
98*a9643ea8Slogwang         /* CLKDIV  = 384000000/ 3/ 16/ br */
99*a9643ea8Slogwang         /* for 384MHz CLKDIV = 8000000 / baudrate; */
100*a9643ea8Slogwang         switch (databits) {
101*a9643ea8Slogwang         case 5:
102*a9643ea8Slogwang     		databits = UART_LCR_5B;
103*a9643ea8Slogwang     		break;
104*a9643ea8Slogwang         case 6:
105*a9643ea8Slogwang     		databits = UART_LCR_6B;
106*a9643ea8Slogwang     		break;
107*a9643ea8Slogwang         case 7:
108*a9643ea8Slogwang     		databits = UART_LCR_7B;
109*a9643ea8Slogwang     		break;
110*a9643ea8Slogwang         case 8:
111*a9643ea8Slogwang     		databits = UART_LCR_8B;
112*a9643ea8Slogwang     		break;
113*a9643ea8Slogwang     	default:
114*a9643ea8Slogwang     		/* Unsupported */
115*a9643ea8Slogwang     		return;
116*a9643ea8Slogwang         }
117*a9643ea8Slogwang 	switch (parity) {
118*a9643ea8Slogwang 	case UART_PARITY_EVEN:	parity = (UART_LCR_PEN|UART_LCR_EVEN); break;
119*a9643ea8Slogwang 	case UART_PARITY_ODD:	parity = (UART_LCR_PEN); break;
120*a9643ea8Slogwang 	case UART_PARITY_NONE:	parity = 0; break;
121*a9643ea8Slogwang 	/* Unsupported */
122*a9643ea8Slogwang 	default:		return;
123*a9643ea8Slogwang 	}
124*a9643ea8Slogwang 
125*a9643ea8Slogwang 	if (bas->rclk && baudrate) {
126*a9643ea8Slogwang         	uart_setreg(bas, UART_CDDL_REG, bas->rclk/16/baudrate);
127*a9643ea8Slogwang 		uart_barrier(bas);
128*a9643ea8Slogwang 	}
129*a9643ea8Slogwang 
130*a9643ea8Slogwang         uart_setreg(bas, UART_LCR_REG, databits |
131*a9643ea8Slogwang 				(stopbits==1?0:UART_LCR_STB_15) |
132*a9643ea8Slogwang        			 	parity);
133*a9643ea8Slogwang 	uart_barrier(bas);
134*a9643ea8Slogwang }
135*a9643ea8Slogwang 
136*a9643ea8Slogwang static void
mtk_uart_term(struct uart_bas * bas)137*a9643ea8Slogwang mtk_uart_term(struct uart_bas *bas)
138*a9643ea8Slogwang {
139*a9643ea8Slogwang         uart_setreg(bas, UART_MCR_REG, 0);
140*a9643ea8Slogwang 	uart_barrier(bas);
141*a9643ea8Slogwang }
142*a9643ea8Slogwang 
143*a9643ea8Slogwang static void
mtk_uart_putc(struct uart_bas * bas,int c)144*a9643ea8Slogwang mtk_uart_putc(struct uart_bas *bas, int c)
145*a9643ea8Slogwang {
146*a9643ea8Slogwang 	char chr;
147*a9643ea8Slogwang 	if (!uart_output) return;
148*a9643ea8Slogwang 	chr = c;
149*a9643ea8Slogwang 	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
150*a9643ea8Slogwang 	uart_setreg(bas, UART_TX_REG, c);
151*a9643ea8Slogwang 	uart_barrier(bas);
152*a9643ea8Slogwang 	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE));
153*a9643ea8Slogwang }
154*a9643ea8Slogwang 
155*a9643ea8Slogwang static int
mtk_uart_rxready(struct uart_bas * bas)156*a9643ea8Slogwang mtk_uart_rxready(struct uart_bas *bas)
157*a9643ea8Slogwang {
158*a9643ea8Slogwang 	if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)
159*a9643ea8Slogwang 		return (1);
160*a9643ea8Slogwang 	return (0);
161*a9643ea8Slogwang }
162*a9643ea8Slogwang 
163*a9643ea8Slogwang static int
mtk_uart_getc(struct uart_bas * bas,struct mtx * hwmtx)164*a9643ea8Slogwang mtk_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
165*a9643ea8Slogwang {
166*a9643ea8Slogwang 	int c;
167*a9643ea8Slogwang 
168*a9643ea8Slogwang 	uart_lock(hwmtx);
169*a9643ea8Slogwang 
170*a9643ea8Slogwang 	while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) {
171*a9643ea8Slogwang 		uart_unlock(hwmtx);
172*a9643ea8Slogwang 		DELAY(10);
173*a9643ea8Slogwang 		uart_lock(hwmtx);
174*a9643ea8Slogwang 	}
175*a9643ea8Slogwang 
176*a9643ea8Slogwang 	c = uart_getreg(bas, UART_RX_REG);
177*a9643ea8Slogwang 
178*a9643ea8Slogwang 	uart_unlock(hwmtx);
179*a9643ea8Slogwang 
180*a9643ea8Slogwang 	return (c);
181*a9643ea8Slogwang }
182*a9643ea8Slogwang 
183*a9643ea8Slogwang /*
184*a9643ea8Slogwang  * High-level UART interface.
185*a9643ea8Slogwang  */
186*a9643ea8Slogwang struct uart_mtk_softc {
187*a9643ea8Slogwang 	struct uart_softc base;
188*a9643ea8Slogwang 	uint8_t ier_mask;
189*a9643ea8Slogwang 	uint8_t ier;
190*a9643ea8Slogwang };
191*a9643ea8Slogwang 
192*a9643ea8Slogwang static int mtk_uart_bus_attach(struct uart_softc *);
193*a9643ea8Slogwang static int mtk_uart_bus_detach(struct uart_softc *);
194*a9643ea8Slogwang static int mtk_uart_bus_flush(struct uart_softc *, int);
195*a9643ea8Slogwang static int mtk_uart_bus_getsig(struct uart_softc *);
196*a9643ea8Slogwang static int mtk_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
197*a9643ea8Slogwang static int mtk_uart_bus_ipend(struct uart_softc *);
198*a9643ea8Slogwang static int mtk_uart_bus_param(struct uart_softc *, int, int, int, int);
199*a9643ea8Slogwang static int mtk_uart_bus_probe(struct uart_softc *);
200*a9643ea8Slogwang static int mtk_uart_bus_receive(struct uart_softc *);
201*a9643ea8Slogwang static int mtk_uart_bus_setsig(struct uart_softc *, int);
202*a9643ea8Slogwang static int mtk_uart_bus_transmit(struct uart_softc *);
203*a9643ea8Slogwang static void mtk_uart_bus_grab(struct uart_softc *);
204*a9643ea8Slogwang static void mtk_uart_bus_ungrab(struct uart_softc *);
205*a9643ea8Slogwang 
206*a9643ea8Slogwang static kobj_method_t uart_mtk_methods[] = {
207*a9643ea8Slogwang 	KOBJMETHOD(uart_attach,		mtk_uart_bus_attach),
208*a9643ea8Slogwang 	KOBJMETHOD(uart_detach,		mtk_uart_bus_detach),
209*a9643ea8Slogwang 	KOBJMETHOD(uart_flush,		mtk_uart_bus_flush),
210*a9643ea8Slogwang 	KOBJMETHOD(uart_getsig,		mtk_uart_bus_getsig),
211*a9643ea8Slogwang 	KOBJMETHOD(uart_ioctl,		mtk_uart_bus_ioctl),
212*a9643ea8Slogwang 	KOBJMETHOD(uart_ipend,		mtk_uart_bus_ipend),
213*a9643ea8Slogwang 	KOBJMETHOD(uart_param,		mtk_uart_bus_param),
214*a9643ea8Slogwang 	KOBJMETHOD(uart_probe,		mtk_uart_bus_probe),
215*a9643ea8Slogwang 	KOBJMETHOD(uart_receive,	mtk_uart_bus_receive),
216*a9643ea8Slogwang 	KOBJMETHOD(uart_setsig,		mtk_uart_bus_setsig),
217*a9643ea8Slogwang 	KOBJMETHOD(uart_transmit,	mtk_uart_bus_transmit),
218*a9643ea8Slogwang 	KOBJMETHOD(uart_grab,		mtk_uart_bus_grab),
219*a9643ea8Slogwang 	KOBJMETHOD(uart_ungrab,		mtk_uart_bus_ungrab),
220*a9643ea8Slogwang 	{ 0, 0 }
221*a9643ea8Slogwang };
222*a9643ea8Slogwang 
223*a9643ea8Slogwang struct uart_class uart_mtk_class = {
224*a9643ea8Slogwang 	"uart_mtk",
225*a9643ea8Slogwang 	uart_mtk_methods,
226*a9643ea8Slogwang 	sizeof(struct uart_mtk_softc),
227*a9643ea8Slogwang 	.uc_ops = &uart_mtk_ops,
228*a9643ea8Slogwang 	.uc_range = 1, /* use hinted range */
229*a9643ea8Slogwang 	.uc_rclk = 0
230*a9643ea8Slogwang };
231*a9643ea8Slogwang 
232*a9643ea8Slogwang static struct ofw_compat_data compat_data[] = {
233*a9643ea8Slogwang 	{ "ralink,rt2880-uart",		(uintptr_t)&uart_mtk_class },
234*a9643ea8Slogwang 	{ "ralink,rt3050-uart",		(uintptr_t)&uart_mtk_class },
235*a9643ea8Slogwang 	{ "ralink,rt3352-uart",		(uintptr_t)&uart_mtk_class },
236*a9643ea8Slogwang 	{ "ralink,rt3883-uart",		(uintptr_t)&uart_mtk_class },
237*a9643ea8Slogwang 	{ "ralink,rt5350-uart",		(uintptr_t)&uart_mtk_class },
238*a9643ea8Slogwang 	{ "ralink,mt7620a-uart",	(uintptr_t)&uart_mtk_class },
239*a9643ea8Slogwang 	{ NULL,				(uintptr_t)NULL },
240*a9643ea8Slogwang };
241*a9643ea8Slogwang UART_FDT_CLASS_AND_DEVICE(compat_data);
242*a9643ea8Slogwang 
243*a9643ea8Slogwang #define	SIGCHG(c, i, s, d)				\
244*a9643ea8Slogwang 	if (c) {					\
245*a9643ea8Slogwang 		i |= (i & s) ? s : s | d;		\
246*a9643ea8Slogwang 	} else {					\
247*a9643ea8Slogwang 		i = (i & s) ? (i & ~s) | d : i;		\
248*a9643ea8Slogwang 	}
249*a9643ea8Slogwang 
250*a9643ea8Slogwang /*
251*a9643ea8Slogwang  * Disable TX interrupt. uart should be locked
252*a9643ea8Slogwang  */
253*a9643ea8Slogwang static __inline void
mtk_uart_disable_txintr(struct uart_softc * sc)254*a9643ea8Slogwang mtk_uart_disable_txintr(struct uart_softc *sc)
255*a9643ea8Slogwang {
256*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
257*a9643ea8Slogwang 	uint8_t cr;
258*a9643ea8Slogwang 
259*a9643ea8Slogwang 	cr = uart_getreg(bas, UART_IER_REG);
260*a9643ea8Slogwang 	cr &= ~UART_IER_ETBEI;
261*a9643ea8Slogwang 	uart_setreg(bas, UART_IER_REG, cr);
262*a9643ea8Slogwang 	uart_barrier(bas);
263*a9643ea8Slogwang }
264*a9643ea8Slogwang 
265*a9643ea8Slogwang /*
266*a9643ea8Slogwang  * Enable TX interrupt. uart should be locked
267*a9643ea8Slogwang  */
268*a9643ea8Slogwang static __inline void
mtk_uart_enable_txintr(struct uart_softc * sc)269*a9643ea8Slogwang mtk_uart_enable_txintr(struct uart_softc *sc)
270*a9643ea8Slogwang {
271*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
272*a9643ea8Slogwang 	uint8_t cr;
273*a9643ea8Slogwang 
274*a9643ea8Slogwang 	cr = uart_getreg(bas, UART_IER_REG);
275*a9643ea8Slogwang 	cr |= UART_IER_ETBEI;
276*a9643ea8Slogwang 	uart_setreg(bas, UART_IER_REG, cr);
277*a9643ea8Slogwang 	uart_barrier(bas);
278*a9643ea8Slogwang }
279*a9643ea8Slogwang 
280*a9643ea8Slogwang static int
mtk_uart_bus_attach(struct uart_softc * sc)281*a9643ea8Slogwang mtk_uart_bus_attach(struct uart_softc *sc)
282*a9643ea8Slogwang {
283*a9643ea8Slogwang 	struct uart_bas *bas;
284*a9643ea8Slogwang 	struct uart_devinfo *di;
285*a9643ea8Slogwang 	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
286*a9643ea8Slogwang 
287*a9643ea8Slogwang 	bas = &sc->sc_bas;
288*a9643ea8Slogwang 
289*a9643ea8Slogwang 	if (!bas->rclk) {
290*a9643ea8Slogwang 		bas->rclk = mtk_soc_get_uartclk();
291*a9643ea8Slogwang 	}
292*a9643ea8Slogwang 
293*a9643ea8Slogwang 	if (sc->sc_sysdev != NULL) {
294*a9643ea8Slogwang 		di = sc->sc_sysdev;
295*a9643ea8Slogwang 		mtk_uart_init(bas, di->baudrate, di->databits, di->stopbits,
296*a9643ea8Slogwang 		    di->parity);
297*a9643ea8Slogwang 	} else {
298*a9643ea8Slogwang 		mtk_uart_init(bas, 57600, 8, 1, 0);
299*a9643ea8Slogwang 	}
300*a9643ea8Slogwang 
301*a9643ea8Slogwang 	sc->sc_rxfifosz = 16;
302*a9643ea8Slogwang 	sc->sc_txfifosz = 16;
303*a9643ea8Slogwang 
304*a9643ea8Slogwang 	(void)mtk_uart_bus_getsig(sc);
305*a9643ea8Slogwang 
306*a9643ea8Slogwang 	/* Enable FIFO */
307*a9643ea8Slogwang 	uart_setreg(bas, UART_FCR_REG,
308*a9643ea8Slogwang 	    uart_getreg(bas, UART_FCR_REG) |
309*a9643ea8Slogwang 	    UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1);
310*a9643ea8Slogwang 	uart_barrier(bas);
311*a9643ea8Slogwang 	/* Enable interrupts */
312*a9643ea8Slogwang 	usc->ier_mask = 0xf0;
313*a9643ea8Slogwang 	uart_setreg(bas, UART_IER_REG,
314*a9643ea8Slogwang 	    UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI);
315*a9643ea8Slogwang 	uart_barrier(bas);
316*a9643ea8Slogwang 
317*a9643ea8Slogwang 	return (0);
318*a9643ea8Slogwang }
319*a9643ea8Slogwang 
320*a9643ea8Slogwang static int
mtk_uart_bus_detach(struct uart_softc * sc)321*a9643ea8Slogwang mtk_uart_bus_detach(struct uart_softc *sc)
322*a9643ea8Slogwang {
323*a9643ea8Slogwang 	return (0);
324*a9643ea8Slogwang }
325*a9643ea8Slogwang 
326*a9643ea8Slogwang static int
mtk_uart_bus_flush(struct uart_softc * sc,int what)327*a9643ea8Slogwang mtk_uart_bus_flush(struct uart_softc *sc, int what)
328*a9643ea8Slogwang {
329*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
330*a9643ea8Slogwang 	uint32_t fcr = uart_getreg(bas, UART_FCR_REG);
331*a9643ea8Slogwang 
332*a9643ea8Slogwang 	if (what & UART_FLUSH_TRANSMITTER) {
333*a9643ea8Slogwang 		uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST);
334*a9643ea8Slogwang 		uart_barrier(bas);
335*a9643ea8Slogwang 	}
336*a9643ea8Slogwang 	if (what & UART_FLUSH_RECEIVER) {
337*a9643ea8Slogwang 		uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST);
338*a9643ea8Slogwang 		uart_barrier(bas);
339*a9643ea8Slogwang 	}
340*a9643ea8Slogwang 	uart_setreg(bas, UART_FCR_REG, fcr);
341*a9643ea8Slogwang 	uart_barrier(bas);
342*a9643ea8Slogwang 	return (0);
343*a9643ea8Slogwang }
344*a9643ea8Slogwang 
345*a9643ea8Slogwang static int
mtk_uart_bus_getsig(struct uart_softc * sc)346*a9643ea8Slogwang mtk_uart_bus_getsig(struct uart_softc *sc)
347*a9643ea8Slogwang {
348*a9643ea8Slogwang 	uint32_t new, old, sig;
349*a9643ea8Slogwang 	uint8_t bes;
350*a9643ea8Slogwang 
351*a9643ea8Slogwang 	return(0);
352*a9643ea8Slogwang 	do {
353*a9643ea8Slogwang 		old = sc->sc_hwsig;
354*a9643ea8Slogwang 		sig = old;
355*a9643ea8Slogwang 		uart_lock(sc->sc_hwmtx);
356*a9643ea8Slogwang 		bes = uart_getreg(&sc->sc_bas, UART_MSR_REG);
357*a9643ea8Slogwang 		uart_unlock(sc->sc_hwmtx);
358*a9643ea8Slogwang 		/* XXX: chip can show delta */
359*a9643ea8Slogwang 		SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS);
360*a9643ea8Slogwang 		SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD);
361*a9643ea8Slogwang 		SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR);
362*a9643ea8Slogwang 		new = sig & ~SER_MASK_DELTA;
363*a9643ea8Slogwang 	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
364*a9643ea8Slogwang 
365*a9643ea8Slogwang 	return (sig);
366*a9643ea8Slogwang }
367*a9643ea8Slogwang 
368*a9643ea8Slogwang static int
mtk_uart_bus_ioctl(struct uart_softc * sc,int request,intptr_t data)369*a9643ea8Slogwang mtk_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
370*a9643ea8Slogwang {
371*a9643ea8Slogwang 	struct uart_bas *bas;
372*a9643ea8Slogwang 	int baudrate, divisor, error;
373*a9643ea8Slogwang 
374*a9643ea8Slogwang 	bas = &sc->sc_bas;
375*a9643ea8Slogwang 	error = 0;
376*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
377*a9643ea8Slogwang 	switch (request) {
378*a9643ea8Slogwang 	case UART_IOCTL_BREAK:
379*a9643ea8Slogwang 		/* TODO: Send BREAK */
380*a9643ea8Slogwang 		break;
381*a9643ea8Slogwang 	case UART_IOCTL_BAUD:
382*a9643ea8Slogwang 		divisor = uart_getreg(bas, UART_CDDL_REG);
383*a9643ea8Slogwang 		baudrate = bas->rclk / (divisor * 16);
384*a9643ea8Slogwang 		*(int*)data = baudrate;
385*a9643ea8Slogwang 		break;
386*a9643ea8Slogwang 	default:
387*a9643ea8Slogwang 		error = EINVAL;
388*a9643ea8Slogwang 		break;
389*a9643ea8Slogwang 	}
390*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
391*a9643ea8Slogwang 	return (error);
392*a9643ea8Slogwang }
393*a9643ea8Slogwang 
394*a9643ea8Slogwang static int
mtk_uart_bus_ipend(struct uart_softc * sc)395*a9643ea8Slogwang mtk_uart_bus_ipend(struct uart_softc *sc)
396*a9643ea8Slogwang {
397*a9643ea8Slogwang 	struct uart_bas *bas;
398*a9643ea8Slogwang 	int ipend;
399*a9643ea8Slogwang 	uint8_t iir, lsr, msr;
400*a9643ea8Slogwang 
401*a9643ea8Slogwang //	breakpoint();
402*a9643ea8Slogwang 
403*a9643ea8Slogwang 	bas = &sc->sc_bas;
404*a9643ea8Slogwang 	ipend = 0;
405*a9643ea8Slogwang 
406*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
407*a9643ea8Slogwang 	iir = uart_getreg(&sc->sc_bas, UART_IIR_REG);
408*a9643ea8Slogwang 	lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG);
409*a9643ea8Slogwang 	uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr);
410*a9643ea8Slogwang 	msr = uart_getreg(&sc->sc_bas, UART_MSR_REG);
411*a9643ea8Slogwang 	uart_setreg(&sc->sc_bas, UART_MSR_REG, msr);
412*a9643ea8Slogwang 	if (iir & UART_IIR_INTP) {
413*a9643ea8Slogwang 		uart_unlock(sc->sc_hwmtx);
414*a9643ea8Slogwang 		return (0);
415*a9643ea8Slogwang 	}
416*a9643ea8Slogwang 	switch ((iir >> 1) & 0x07) {
417*a9643ea8Slogwang 	case UART_IIR_ID_THRE:
418*a9643ea8Slogwang 		ipend |= SER_INT_TXIDLE;
419*a9643ea8Slogwang 		break;
420*a9643ea8Slogwang 	case UART_IIR_ID_DR2:
421*a9643ea8Slogwang 		mtk_uart_bus_flush(sc, UART_FLUSH_RECEIVER);
422*a9643ea8Slogwang 		/* passthrough */
423*a9643ea8Slogwang 	case UART_IIR_ID_DR:
424*a9643ea8Slogwang 		ipend |= SER_INT_RXREADY;
425*a9643ea8Slogwang 		break;
426*a9643ea8Slogwang 	case UART_IIR_ID_MST:
427*a9643ea8Slogwang 	case UART_IIR_ID_LINESTATUS:
428*a9643ea8Slogwang 		ipend |= SER_INT_SIGCHG;
429*a9643ea8Slogwang 		if (lsr & UART_LSR_BI)
430*a9643ea8Slogwang 			ipend |= SER_INT_BREAK;
431*a9643ea8Slogwang 		if (lsr & UART_LSR_OE)
432*a9643ea8Slogwang 			ipend |= SER_INT_OVERRUN;
433*a9643ea8Slogwang 		break;
434*a9643ea8Slogwang 	default:
435*a9643ea8Slogwang 		/* XXX: maybe return error here */
436*a9643ea8Slogwang 		break;
437*a9643ea8Slogwang 	}
438*a9643ea8Slogwang 
439*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
440*a9643ea8Slogwang 
441*a9643ea8Slogwang 	return (ipend);
442*a9643ea8Slogwang }
443*a9643ea8Slogwang 
444*a9643ea8Slogwang static int
mtk_uart_bus_param(struct uart_softc * sc,int baudrate,int databits,int stopbits,int parity)445*a9643ea8Slogwang mtk_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
446*a9643ea8Slogwang     int stopbits, int parity)
447*a9643ea8Slogwang {
448*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
449*a9643ea8Slogwang 	mtk_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity);
450*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
451*a9643ea8Slogwang 	return (0);
452*a9643ea8Slogwang }
453*a9643ea8Slogwang 
454*a9643ea8Slogwang static int
mtk_uart_bus_probe(struct uart_softc * sc)455*a9643ea8Slogwang mtk_uart_bus_probe(struct uart_softc *sc)
456*a9643ea8Slogwang {
457*a9643ea8Slogwang 	int error;
458*a9643ea8Slogwang 
459*a9643ea8Slogwang 	error = mtk_uart_probe(&sc->sc_bas);
460*a9643ea8Slogwang 	if (error)
461*a9643ea8Slogwang 		return (error);
462*a9643ea8Slogwang 
463*a9643ea8Slogwang 	device_set_desc(sc->sc_dev, "MTK UART Controller");
464*a9643ea8Slogwang 
465*a9643ea8Slogwang 	return (0);
466*a9643ea8Slogwang }
467*a9643ea8Slogwang 
468*a9643ea8Slogwang static int
mtk_uart_bus_receive(struct uart_softc * sc)469*a9643ea8Slogwang mtk_uart_bus_receive(struct uart_softc *sc)
470*a9643ea8Slogwang {
471*a9643ea8Slogwang 	struct uart_bas *bas;
472*a9643ea8Slogwang 	int xc;
473*a9643ea8Slogwang 	uint8_t lsr;
474*a9643ea8Slogwang 
475*a9643ea8Slogwang 	bas = &sc->sc_bas;
476*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
477*a9643ea8Slogwang 	lsr = uart_getreg(bas, UART_LSR_REG);
478*a9643ea8Slogwang 	while ((lsr & UART_LSR_DR)) {
479*a9643ea8Slogwang 		if (uart_rx_full(sc)) {
480*a9643ea8Slogwang 			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
481*a9643ea8Slogwang 			break;
482*a9643ea8Slogwang 		}
483*a9643ea8Slogwang 		xc = 0;
484*a9643ea8Slogwang 		xc = uart_getreg(bas, UART_RX_REG);
485*a9643ea8Slogwang 		if (lsr & UART_LSR_FE)
486*a9643ea8Slogwang 			xc |= UART_STAT_FRAMERR;
487*a9643ea8Slogwang 		if (lsr & UART_LSR_PE)
488*a9643ea8Slogwang 			xc |= UART_STAT_PARERR;
489*a9643ea8Slogwang 		if (lsr & UART_LSR_OE)
490*a9643ea8Slogwang 			xc |= UART_STAT_OVERRUN;
491*a9643ea8Slogwang 		uart_barrier(bas);
492*a9643ea8Slogwang 		uart_rx_put(sc, xc);
493*a9643ea8Slogwang 		lsr = uart_getreg(bas, UART_LSR_REG);
494*a9643ea8Slogwang 	}
495*a9643ea8Slogwang 
496*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
497*a9643ea8Slogwang 	return (0);
498*a9643ea8Slogwang }
499*a9643ea8Slogwang 
500*a9643ea8Slogwang static int
mtk_uart_bus_setsig(struct uart_softc * sc,int sig)501*a9643ea8Slogwang mtk_uart_bus_setsig(struct uart_softc *sc, int sig)
502*a9643ea8Slogwang {
503*a9643ea8Slogwang 	/* TODO: implement (?) */
504*a9643ea8Slogwang 	return (sig);
505*a9643ea8Slogwang }
506*a9643ea8Slogwang 
507*a9643ea8Slogwang static int
mtk_uart_bus_transmit(struct uart_softc * sc)508*a9643ea8Slogwang mtk_uart_bus_transmit(struct uart_softc *sc)
509*a9643ea8Slogwang {
510*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
511*a9643ea8Slogwang 	int i;
512*a9643ea8Slogwang 
513*a9643ea8Slogwang 	if (!uart_output) return (0);
514*a9643ea8Slogwang 
515*a9643ea8Slogwang 	bas = &sc->sc_bas;
516*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
517*a9643ea8Slogwang 	while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0);
518*a9643ea8Slogwang 	mtk_uart_enable_txintr(sc);
519*a9643ea8Slogwang 	for (i = 0; i < sc->sc_txdatasz; i++) {
520*a9643ea8Slogwang 		uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]);
521*a9643ea8Slogwang 		uart_barrier(bas);
522*a9643ea8Slogwang 	}
523*a9643ea8Slogwang 	sc->sc_txbusy = 1;
524*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
525*a9643ea8Slogwang 	return (0);
526*a9643ea8Slogwang }
527*a9643ea8Slogwang 
528*a9643ea8Slogwang void
mtk_uart_bus_grab(struct uart_softc * sc)529*a9643ea8Slogwang mtk_uart_bus_grab(struct uart_softc *sc)
530*a9643ea8Slogwang {
531*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
532*a9643ea8Slogwang 	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
533*a9643ea8Slogwang 
534*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
535*a9643ea8Slogwang 	usc->ier = uart_getreg(bas, UART_IER_REG);
536*a9643ea8Slogwang 	uart_setreg(bas, UART_IER_REG, usc->ier & usc->ier_mask);
537*a9643ea8Slogwang 	uart_barrier(bas);
538*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
539*a9643ea8Slogwang }
540*a9643ea8Slogwang 
541*a9643ea8Slogwang void
mtk_uart_bus_ungrab(struct uart_softc * sc)542*a9643ea8Slogwang mtk_uart_bus_ungrab(struct uart_softc *sc)
543*a9643ea8Slogwang {
544*a9643ea8Slogwang 	struct uart_mtk_softc *usc = (struct uart_mtk_softc *)sc;
545*a9643ea8Slogwang 	struct uart_bas *bas = &sc->sc_bas;
546*a9643ea8Slogwang 
547*a9643ea8Slogwang 	uart_lock(sc->sc_hwmtx);
548*a9643ea8Slogwang 	uart_setreg(bas, UART_IER_REG, usc->ier);
549*a9643ea8Slogwang 	uart_barrier(bas);
550*a9643ea8Slogwang 	uart_unlock(sc->sc_hwmtx);
551*a9643ea8Slogwang }
552