1248843Sadrian/*-
2248843Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3248843Sadrian * All rights reserved.
4248843Sadrian *
5248843Sadrian * Redistribution and use in source and binary forms, with or without
6248843Sadrian * modification, are permitted provided that the following conditions
7248843Sadrian * are met:
8248843Sadrian *
9248843Sadrian * 1. Redistributions of source code must retain the above copyright
10248843Sadrian *    notice, this list of conditions and the following disclaimer.
11248843Sadrian * 2. Redistributions in binary form must reproduce the above copyright
12248843Sadrian *    notice, this list of conditions and the following disclaimer in the
13248843Sadrian *    documentation and/or other materials provided with the distribution.
14248843Sadrian *
15248843Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16248843Sadrian * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17248843Sadrian * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18248843Sadrian * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19248843Sadrian * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20248843Sadrian * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21248843Sadrian * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22248843Sadrian * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23248843Sadrian * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24248843Sadrian * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25248843Sadrian */
26248843Sadrian
27248843Sadrian#include <sys/cdefs.h>
28248843Sadrian__FBSDID("$FreeBSD: releng/10.3/sys/mips/atheros/uart_dev_ar933x.c 262649 2014-03-01 04:16:54Z imp $");
29248843Sadrian
30248843Sadrian#include <sys/param.h>
31248843Sadrian#include <sys/systm.h>
32248843Sadrian#include <sys/bus.h>
33248843Sadrian#include <sys/conf.h>
34248843Sadrian#include <machine/bus.h>
35248843Sadrian
36248843Sadrian#include <dev/uart/uart.h>
37248843Sadrian#include <dev/uart/uart_cpu.h>
38248843Sadrian#include <dev/uart/uart_bus.h>
39248843Sadrian
40248843Sadrian#include <mips/atheros/ar933x_uart.h>
41248843Sadrian
42248843Sadrian#include "uart_if.h"
43248843Sadrian
44248926Sadrian/*
45248926Sadrian * Default system clock is 25MHz; see ar933x_chip.c for how
46248926Sadrian * the startup process determines whether it's 25MHz or 40MHz.
47248926Sadrian */
48248926Sadrian#define	DEFAULT_RCLK	(25 * 1000 * 1000)
49248843Sadrian
50248843Sadrian#define	ar933x_getreg(bas, reg)           \
51248926Sadrian	bus_space_read_4((bas)->bst, (bas)->bsh, reg)
52248843Sadrian#define	ar933x_setreg(bas, reg, value)    \
53248926Sadrian	bus_space_write_4((bas)->bst, (bas)->bsh, reg, value)
54248843Sadrian
55248843Sadrian
56248843Sadrian
57248843Sadrianstatic int
58248843Sadrianar933x_drain(struct uart_bas *bas, int what)
59248843Sadrian{
60249093Sadrian	int limit;
61248843Sadrian
62248843Sadrian	if (what & UART_DRAIN_TRANSMITTER) {
63248843Sadrian		limit = 10*1024;
64249093Sadrian
65249093Sadrian		/* Loop over until the TX FIFO shows entirely clear */
66249093Sadrian		while (--limit) {
67249093Sadrian			if ((ar933x_getreg(bas, AR933X_UART_CS_REG)
68249093Sadrian			    & AR933X_UART_CS_TX_BUSY) == 0)
69249093Sadrian				break;
70249093Sadrian		}
71248843Sadrian		if (limit == 0) {
72248843Sadrian			return (EIO);
73248843Sadrian		}
74248843Sadrian	}
75248843Sadrian
76248843Sadrian	if (what & UART_DRAIN_RECEIVER) {
77248843Sadrian		limit=10*4096;
78249093Sadrian		while (--limit) {
79249093Sadrian
80249093Sadrian			/* XXX duplicated from ar933x_getc() */
81249093Sadrian			/* XXX TODO: refactor! */
82249093Sadrian
83249093Sadrian			/* If there's nothing to read, stop! */
84249093Sadrian			if ((ar933x_getreg(bas, AR933X_UART_DATA_REG) &
85249093Sadrian			    AR933X_UART_DATA_RX_CSR) == 0) {
86249093Sadrian				break;
87249093Sadrian			}
88249093Sadrian
89249093Sadrian			/* Read the top of the RX FIFO */
90249093Sadrian			(void) ar933x_getreg(bas, AR933X_UART_DATA_REG);
91249093Sadrian
92249093Sadrian			/* Remove that entry from said RX FIFO */
93249093Sadrian			ar933x_setreg(bas, AR933X_UART_DATA_REG,
94249093Sadrian			    AR933X_UART_DATA_RX_CSR);
95249093Sadrian
96248843Sadrian			uart_barrier(bas);
97249093Sadrian			DELAY(2);
98248843Sadrian		}
99248843Sadrian		if (limit == 0) {
100248843Sadrian			return (EIO);
101248843Sadrian		}
102248843Sadrian	}
103248843Sadrian	return (0);
104248843Sadrian}
105248843Sadrian
106248843Sadrian/*
107248927Sadrian * Calculate the baud from the given chip configuration parameters.
108248927Sadrian */
109248927Sadrianstatic unsigned long
110248927Sadrianar933x_uart_get_baud(unsigned int clk, unsigned int scale,
111248927Sadrian    unsigned int step)
112248927Sadrian{
113248927Sadrian	uint64_t t;
114248927Sadrian	uint32_t div;
115248927Sadrian
116248927Sadrian	div = (2 << 16) * (scale + 1);
117248927Sadrian	t = clk;
118248927Sadrian	t *= step;
119248927Sadrian	t += (div / 2);
120248927Sadrian	t = t / div;
121248927Sadrian
122248927Sadrian	return (t);
123248927Sadrian}
124248927Sadrian
125248927Sadrian/*
126248927Sadrian * Calculate the scale/step with the lowest possible deviation from
127248927Sadrian * the target baudrate.
128248927Sadrian */
129248927Sadrianstatic void
130248927Sadrianar933x_uart_get_scale_step(struct uart_bas *bas, unsigned int baud,
131248927Sadrian    unsigned int *scale, unsigned int *step)
132248927Sadrian{
133248927Sadrian	unsigned int tscale;
134248927Sadrian	uint32_t clk;
135248927Sadrian	long min_diff;
136248927Sadrian
137248927Sadrian	clk = bas->rclk;
138248927Sadrian	*scale = 0;
139248927Sadrian	*step = 0;
140248927Sadrian
141248927Sadrian	min_diff = baud;
142248927Sadrian	for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
143248927Sadrian		uint64_t tstep;
144248927Sadrian		int diff;
145248927Sadrian
146248927Sadrian		tstep = baud * (tscale + 1);
147248927Sadrian		tstep *= (2 << 16);
148248927Sadrian		tstep = tstep / clk;
149248927Sadrian
150248927Sadrian		if (tstep > AR933X_UART_MAX_STEP)
151248927Sadrian			break;
152248927Sadrian
153248927Sadrian		diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
154248927Sadrian		if (diff < min_diff) {
155248927Sadrian			min_diff = diff;
156248927Sadrian			*scale = tscale;
157248927Sadrian			*step = tstep;
158248927Sadrian		}
159248927Sadrian	}
160248927Sadrian}
161248927Sadrian
162248843Sadrianstatic int
163248843Sadrianar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
164248843Sadrian    int parity)
165248843Sadrian{
166248927Sadrian	/* UART always 8 bits */
167248843Sadrian
168248927Sadrian	/* UART always 1 stop bit */
169248843Sadrian
170248927Sadrian	/* UART parity is controllable by bits 0:1, ignore for now */
171248927Sadrian
172248927Sadrian	/* Set baudrate if required. */
173248843Sadrian	if (baudrate > 0) {
174248927Sadrian		uint32_t clock_scale, clock_step;
175248927Sadrian
176248927Sadrian		/* Find the best fit for the given baud rate */
177248927Sadrian		ar933x_uart_get_scale_step(bas, baudrate, &clock_scale,
178248927Sadrian		    &clock_step);
179248927Sadrian
180248927Sadrian		/*
181248927Sadrian		 * Program the clock register in its entirety - no need
182248927Sadrian		 * for Read-Modify-Write.
183248927Sadrian		 */
184248927Sadrian		ar933x_setreg(bas, AR933X_UART_CLOCK_REG,
185248927Sadrian		    ((clock_scale & AR933X_UART_CLOCK_SCALE_M)
186248927Sadrian		      << AR933X_UART_CLOCK_SCALE_S) |
187248927Sadrian		    (clock_step & AR933X_UART_CLOCK_STEP_M));
188248843Sadrian	}
189248843Sadrian
190248843Sadrian	uart_barrier(bas);
191248843Sadrian	return (0);
192248843Sadrian}
193248843Sadrian
194248927Sadrian
195248843Sadrian/*
196248843Sadrian * Low-level UART interface.
197248843Sadrian */
198248843Sadrianstatic int ar933x_probe(struct uart_bas *bas);
199248843Sadrianstatic void ar933x_init(struct uart_bas *bas, int, int, int, int);
200248843Sadrianstatic void ar933x_term(struct uart_bas *bas);
201248843Sadrianstatic void ar933x_putc(struct uart_bas *bas, int);
202248843Sadrianstatic int ar933x_rxready(struct uart_bas *bas);
203248843Sadrianstatic int ar933x_getc(struct uart_bas *bas, struct mtx *);
204248843Sadrian
205248843Sadrianstatic struct uart_ops uart_ar933x_ops = {
206248843Sadrian	.probe = ar933x_probe,
207248843Sadrian	.init = ar933x_init,
208248843Sadrian	.term = ar933x_term,
209248843Sadrian	.putc = ar933x_putc,
210248843Sadrian	.rxready = ar933x_rxready,
211248843Sadrian	.getc = ar933x_getc,
212248843Sadrian};
213248843Sadrian
214248843Sadrianstatic int
215248843Sadrianar933x_probe(struct uart_bas *bas)
216248843Sadrian{
217248843Sadrian
218248927Sadrian	/* We always know this will be here */
219248843Sadrian	return (0);
220248843Sadrian}
221248843Sadrian
222248843Sadrianstatic void
223248843Sadrianar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
224248843Sadrian    int parity)
225248843Sadrian{
226248927Sadrian	uint32_t reg;
227248843Sadrian
228248927Sadrian	/* Setup default parameters */
229248843Sadrian	ar933x_param(bas, baudrate, databits, stopbits, parity);
230248843Sadrian
231248927Sadrian	/* XXX Force enable UART in case it was disabled */
232248843Sadrian
233248927Sadrian	/* Disable all interrupts */
234248927Sadrian	ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000);
235248843Sadrian
236248927Sadrian	/* Disable the host interrupt */
237248927Sadrian	reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
238248927Sadrian	reg &= ~AR933X_UART_CS_HOST_INT_EN;
239248927Sadrian	ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
240248927Sadrian
241248843Sadrian	uart_barrier(bas);
242248843Sadrian
243248927Sadrian	/* XXX Set RTS/DTR? */
244248843Sadrian}
245248843Sadrian
246248927Sadrian/*
247248927Sadrian * Detach from console.
248248927Sadrian */
249248843Sadrianstatic void
250248843Sadrianar933x_term(struct uart_bas *bas)
251248843Sadrian{
252248927Sadrian
253248927Sadrian	/* XXX TODO */
254248843Sadrian}
255248843Sadrian
256248843Sadrianstatic void
257248843Sadrianar933x_putc(struct uart_bas *bas, int c)
258248843Sadrian{
259248843Sadrian	int limit;
260248843Sadrian
261248843Sadrian	limit = 250000;
262248843Sadrian
263248843Sadrian	/* Wait for space in the TX FIFO */
264248843Sadrian	while ( ((ar933x_getreg(bas, AR933X_UART_DATA_REG) &
265248843Sadrian	    AR933X_UART_DATA_TX_CSR) == 0) && --limit)
266248843Sadrian		DELAY(4);
267248843Sadrian
268248843Sadrian	/* Write the actual byte */
269248843Sadrian	ar933x_setreg(bas, AR933X_UART_DATA_REG,
270248843Sadrian	    (c & 0xff) | AR933X_UART_DATA_TX_CSR);
271248843Sadrian}
272248843Sadrian
273248843Sadrianstatic int
274248843Sadrianar933x_rxready(struct uart_bas *bas)
275248843Sadrian{
276248843Sadrian
277248843Sadrian	/* Wait for a character to come ready */
278248843Sadrian	return (!!(ar933x_getreg(bas, AR933X_UART_DATA_REG)
279248843Sadrian	    & AR933X_UART_DATA_RX_CSR));
280248843Sadrian}
281248843Sadrian
282248843Sadrianstatic int
283248843Sadrianar933x_getc(struct uart_bas *bas, struct mtx *hwmtx)
284248843Sadrian{
285248843Sadrian	int c;
286248843Sadrian
287248843Sadrian	uart_lock(hwmtx);
288248843Sadrian
289248843Sadrian	/* Wait for a character to come ready */
290248843Sadrian	while ((ar933x_getreg(bas, AR933X_UART_DATA_REG) &
291248843Sadrian	    AR933X_UART_DATA_RX_CSR) == 0) {
292248843Sadrian		uart_unlock(hwmtx);
293248843Sadrian		DELAY(4);
294248843Sadrian		uart_lock(hwmtx);
295248843Sadrian	}
296248843Sadrian
297248843Sadrian	/* Read the top of the RX FIFO */
298248843Sadrian	c = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff;
299248843Sadrian
300248843Sadrian	/* Remove that entry from said RX FIFO */
301248843Sadrian	ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
302248843Sadrian
303248843Sadrian	uart_unlock(hwmtx);
304248843Sadrian
305248843Sadrian	return (c);
306248843Sadrian}
307248843Sadrian
308248843Sadrian/*
309248843Sadrian * High-level UART interface.
310248843Sadrian */
311248843Sadrianstruct ar933x_softc {
312248843Sadrian	struct uart_softc base;
313248926Sadrian
314248843Sadrian	uint32_t	u_ier;
315248843Sadrian};
316248843Sadrian
317248843Sadrianstatic int ar933x_bus_attach(struct uart_softc *);
318248843Sadrianstatic int ar933x_bus_detach(struct uart_softc *);
319248843Sadrianstatic int ar933x_bus_flush(struct uart_softc *, int);
320248843Sadrianstatic int ar933x_bus_getsig(struct uart_softc *);
321248843Sadrianstatic int ar933x_bus_ioctl(struct uart_softc *, int, intptr_t);
322248843Sadrianstatic int ar933x_bus_ipend(struct uart_softc *);
323248843Sadrianstatic int ar933x_bus_param(struct uart_softc *, int, int, int, int);
324248843Sadrianstatic int ar933x_bus_probe(struct uart_softc *);
325248843Sadrianstatic int ar933x_bus_receive(struct uart_softc *);
326248843Sadrianstatic int ar933x_bus_setsig(struct uart_softc *, int);
327248843Sadrianstatic int ar933x_bus_transmit(struct uart_softc *);
328262649Simpstatic void ar933x_bus_grab(struct uart_softc *);
329262649Simpstatic void ar933x_bus_ungrab(struct uart_softc *);
330248843Sadrian
331248843Sadrianstatic kobj_method_t ar933x_methods[] = {
332248843Sadrian	KOBJMETHOD(uart_attach,		ar933x_bus_attach),
333248843Sadrian	KOBJMETHOD(uart_detach,		ar933x_bus_detach),
334248843Sadrian	KOBJMETHOD(uart_flush,		ar933x_bus_flush),
335248843Sadrian	KOBJMETHOD(uart_getsig,		ar933x_bus_getsig),
336248843Sadrian	KOBJMETHOD(uart_ioctl,		ar933x_bus_ioctl),
337248843Sadrian	KOBJMETHOD(uart_ipend,		ar933x_bus_ipend),
338248843Sadrian	KOBJMETHOD(uart_param,		ar933x_bus_param),
339248843Sadrian	KOBJMETHOD(uart_probe,		ar933x_bus_probe),
340248843Sadrian	KOBJMETHOD(uart_receive,	ar933x_bus_receive),
341248843Sadrian	KOBJMETHOD(uart_setsig,		ar933x_bus_setsig),
342248843Sadrian	KOBJMETHOD(uart_transmit,	ar933x_bus_transmit),
343262649Simp	KOBJMETHOD(uart_grab,		ar933x_bus_grab),
344262649Simp	KOBJMETHOD(uart_ungrab,		ar933x_bus_ungrab),
345248843Sadrian	{ 0, 0 }
346248843Sadrian};
347248843Sadrian
348248843Sadrianstruct uart_class uart_ar933x_class = {
349248843Sadrian	"ar933x",
350248843Sadrian	ar933x_methods,
351248843Sadrian	sizeof(struct ar933x_softc),
352248843Sadrian	.uc_ops = &uart_ar933x_ops,
353248843Sadrian	.uc_range = 8,
354248843Sadrian	.uc_rclk = DEFAULT_RCLK
355248843Sadrian};
356248843Sadrian
357248843Sadrian#define	SIGCHG(c, i, s, d)				\
358248843Sadrian	if (c) {					\
359248843Sadrian		i |= (i & s) ? s : s | d;		\
360248843Sadrian	} else {					\
361248843Sadrian		i = (i & s) ? (i & ~s) | d : i;		\
362248843Sadrian	}
363248843Sadrian
364248843Sadrianstatic int
365248843Sadrianar933x_bus_attach(struct uart_softc *sc)
366248843Sadrian{
367249120Sadrian	struct ar933x_softc *u = (struct ar933x_softc *)sc;
368249120Sadrian	struct uart_bas *bas = &sc->sc_bas;
369249120Sadrian	uint32_t reg;
370249120Sadrian
371249093Sadrian	/* XXX TODO: flush transmitter */
372248843Sadrian
373249120Sadrian	/*
374249120Sadrian	 * Setup initial interrupt notifications.
375249120Sadrian	 *
376249120Sadrian	 * XXX for now, just RX FIFO valid.
377249120Sadrian	 * Later on (when they're handled), also handle
378249120Sadrian	 * RX errors/overflow.
379249120Sadrian	 */
380249120Sadrian	u->u_ier = AR933X_UART_INT_RX_VALID;
381248843Sadrian
382249120Sadrian	/* Enable RX interrupts to kick-start things */
383249120Sadrian	ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier);
384248843Sadrian
385249120Sadrian	/* Enable the host interrupt now */
386249120Sadrian	reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
387249120Sadrian	reg |= AR933X_UART_CS_HOST_INT_EN;
388249120Sadrian	ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
389249120Sadrian
390248843Sadrian	return (0);
391248843Sadrian}
392248843Sadrian
393248843Sadrianstatic int
394248843Sadrianar933x_bus_detach(struct uart_softc *sc)
395248843Sadrian{
396249120Sadrian	struct uart_bas *bas = &sc->sc_bas;
397249120Sadrian	uint32_t reg;
398248843Sadrian
399249120Sadrian	/* Disable all interrupts */
400249120Sadrian	ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000);
401249120Sadrian
402249120Sadrian	/* Disable the host interrupt */
403249120Sadrian	reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
404249120Sadrian	reg &= ~AR933X_UART_CS_HOST_INT_EN;
405249120Sadrian	ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
406248843Sadrian	uart_barrier(bas);
407249093Sadrian
408248843Sadrian	return (0);
409248843Sadrian}
410248843Sadrian
411248843Sadrianstatic int
412248843Sadrianar933x_bus_flush(struct uart_softc *sc, int what)
413248843Sadrian{
414248843Sadrian	struct uart_bas *bas;
415248843Sadrian
416248843Sadrian	bas = &sc->sc_bas;
417248843Sadrian	uart_lock(sc->sc_hwmtx);
418249093Sadrian	ar933x_drain(bas, what);
419248843Sadrian	uart_unlock(sc->sc_hwmtx);
420249093Sadrian
421249093Sadrian	return (0);
422248843Sadrian}
423248843Sadrian
424248843Sadrianstatic int
425248843Sadrianar933x_bus_getsig(struct uart_softc *sc)
426248843Sadrian{
427249093Sadrian	uint32_t sig = sc->sc_hwsig;
428248843Sadrian
429249093Sadrian	/*
430249093Sadrian	 * For now, let's just return that DSR/DCD/CTS is asserted.
431249093Sadrian	 *
432249093Sadrian	 * XXX TODO: actually verify whether this is correct!
433249093Sadrian	 */
434249093Sadrian	SIGCHG(1, sig, SER_DSR, SER_DDSR);
435249093Sadrian	SIGCHG(1, sig, SER_CTS, SER_DCTS);
436249093Sadrian	SIGCHG(1, sig, SER_DCD, SER_DDCD);
437249093Sadrian	SIGCHG(1, sig,  SER_RI,  SER_DRI);
438249093Sadrian
439249093Sadrian	sc->sc_hwsig = sig & ~SER_MASK_DELTA;
440249093Sadrian
441248843Sadrian	return (sig);
442248843Sadrian}
443248843Sadrian
444248843Sadrianstatic int
445248843Sadrianar933x_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
446248843Sadrian{
447248843Sadrian#if 0
448248843Sadrian	struct uart_bas *bas;
449248843Sadrian	int baudrate, divisor, error;
450248843Sadrian	uint8_t efr, lcr;
451248843Sadrian
452248843Sadrian	bas = &sc->sc_bas;
453248843Sadrian	error = 0;
454248843Sadrian	uart_lock(sc->sc_hwmtx);
455248843Sadrian	switch (request) {
456248843Sadrian	case UART_IOCTL_BREAK:
457248843Sadrian		lcr = uart_getreg(bas, REG_LCR);
458248843Sadrian		if (data)
459248843Sadrian			lcr |= LCR_SBREAK;
460248843Sadrian		else
461248843Sadrian			lcr &= ~LCR_SBREAK;
462248843Sadrian		uart_setreg(bas, REG_LCR, lcr);
463248843Sadrian		uart_barrier(bas);
464248843Sadrian		break;
465248843Sadrian	case UART_IOCTL_IFLOW:
466248843Sadrian		lcr = uart_getreg(bas, REG_LCR);
467248843Sadrian		uart_barrier(bas);
468248843Sadrian		uart_setreg(bas, REG_LCR, 0xbf);
469248843Sadrian		uart_barrier(bas);
470248843Sadrian		efr = uart_getreg(bas, REG_EFR);
471248843Sadrian		if (data)
472248843Sadrian			efr |= EFR_RTS;
473248843Sadrian		else
474248843Sadrian			efr &= ~EFR_RTS;
475248843Sadrian		uart_setreg(bas, REG_EFR, efr);
476248843Sadrian		uart_barrier(bas);
477248843Sadrian		uart_setreg(bas, REG_LCR, lcr);
478248843Sadrian		uart_barrier(bas);
479248843Sadrian		break;
480248843Sadrian	case UART_IOCTL_OFLOW:
481248843Sadrian		lcr = uart_getreg(bas, REG_LCR);
482248843Sadrian		uart_barrier(bas);
483248843Sadrian		uart_setreg(bas, REG_LCR, 0xbf);
484248843Sadrian		uart_barrier(bas);
485248843Sadrian		efr = uart_getreg(bas, REG_EFR);
486248843Sadrian		if (data)
487248843Sadrian			efr |= EFR_CTS;
488248843Sadrian		else
489248843Sadrian			efr &= ~EFR_CTS;
490248843Sadrian		uart_setreg(bas, REG_EFR, efr);
491248843Sadrian		uart_barrier(bas);
492248843Sadrian		uart_setreg(bas, REG_LCR, lcr);
493248843Sadrian		uart_barrier(bas);
494248843Sadrian		break;
495248843Sadrian	case UART_IOCTL_BAUD:
496248843Sadrian		lcr = uart_getreg(bas, REG_LCR);
497248843Sadrian		uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
498248843Sadrian		uart_barrier(bas);
499248843Sadrian		divisor = uart_getreg(bas, REG_DLL) |
500248843Sadrian		    (uart_getreg(bas, REG_DLH) << 8);
501248843Sadrian		uart_barrier(bas);
502248843Sadrian		uart_setreg(bas, REG_LCR, lcr);
503248843Sadrian		uart_barrier(bas);
504248843Sadrian		baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0;
505248843Sadrian		if (baudrate > 0)
506248843Sadrian			*(int*)data = baudrate;
507248843Sadrian		else
508248843Sadrian			error = ENXIO;
509248843Sadrian		break;
510248843Sadrian	default:
511248843Sadrian		error = EINVAL;
512248843Sadrian		break;
513248843Sadrian	}
514248843Sadrian	uart_unlock(sc->sc_hwmtx);
515248843Sadrian	return (error);
516248843Sadrian#endif
517248843Sadrian	return (ENXIO);
518248843Sadrian}
519248843Sadrian
520249093Sadrian/*
521249093Sadrian * Bus interrupt handler.
522249093Sadrian *
523249093Sadrian * For now, system interrupts are disabled.
524249093Sadrian * So this is just called from a callout in uart_core.c
525249093Sadrian * to poll various state.
526249093Sadrian */
527248843Sadrianstatic int
528248843Sadrianar933x_bus_ipend(struct uart_softc *sc)
529248843Sadrian{
530249120Sadrian	struct ar933x_softc *u = (struct ar933x_softc *)sc;
531249093Sadrian	struct uart_bas *bas = &sc->sc_bas;
532249093Sadrian	int ipend = 0;
533249120Sadrian	uint32_t isr;
534248843Sadrian
535248843Sadrian	uart_lock(sc->sc_hwmtx);
536249093Sadrian
537249093Sadrian	/*
538249120Sadrian	 * Fetch/ACK the ISR status.
539249093Sadrian	 */
540249120Sadrian	isr = ar933x_getreg(bas, AR933X_UART_INT_REG);
541249120Sadrian	ar933x_setreg(bas, AR933X_UART_INT_REG, isr);
542249120Sadrian	uart_barrier(bas);
543249120Sadrian
544249120Sadrian	/*
545249120Sadrian	 * RX ready - notify upper layer.
546249120Sadrian	 */
547249120Sadrian	if (isr & AR933X_UART_INT_RX_VALID) {
548249093Sadrian		ipend |= SER_INT_RXREADY;
549248843Sadrian	}
550249120Sadrian
551249093Sadrian	/*
552249120Sadrian	 * If we get this interrupt, we should disable
553249120Sadrian	 * it from the interrupt mask and inform the uart
554249120Sadrian	 * driver appropriately.
555249120Sadrian	 *
556249120Sadrian	 * We can't keep setting SER_INT_TXIDLE or SER_INT_SIGCHG
557249120Sadrian	 * all the time or IO stops working.  So we will always
558249120Sadrian	 * clear this interrupt if we get it, then we only signal
559249120Sadrian	 * the upper layer if we were doing active TX in the
560249120Sadrian	 * first place.
561249120Sadrian	 *
562249120Sadrian	 * Also, the name is misleading.  This actually means
563249120Sadrian	 * "the FIFO is almost empty."  So if we just write some
564249120Sadrian	 * more data to the FIFO without checking whether it can
565249120Sadrian	 * take said data, we'll overflow the thing.
566249120Sadrian	 *
567249120Sadrian	 * Unfortunately the FreeBSD uart device has no concept of
568249120Sadrian	 * partial UART writes - it expects that the whole buffer
569249120Sadrian	 * is written to the hardware.  Thus for now, ar933x_bus_transmit()
570249120Sadrian	 * will wait for the FIFO to finish draining before it pushes
571249120Sadrian	 * more frames into it.
572249120Sadrian	 */
573249120Sadrian	if (isr & AR933X_UART_INT_TX_EMPTY) {
574249120Sadrian		/*
575249120Sadrian		 * Update u_ier to disable TX notifications; update hardware
576249120Sadrian		 */
577249120Sadrian		u->u_ier &= ~AR933X_UART_INT_TX_EMPTY;
578249120Sadrian		ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier);
579249120Sadrian		uart_barrier(bas);
580249120Sadrian	}
581249120Sadrian
582249120Sadrian	/*
583249093Sadrian	 * Only signal TX idle if we're not busy transmitting.
584249093Sadrian	 */
585249093Sadrian	if (sc->sc_txbusy) {
586249120Sadrian		if (isr & AR933X_UART_INT_TX_EMPTY) {
587248843Sadrian			ipend |= SER_INT_TXIDLE;
588249093Sadrian		} else {
589248843Sadrian			ipend |= SER_INT_SIGCHG;
590249093Sadrian		}
591248843Sadrian	}
592249093Sadrian
593248843Sadrian	uart_unlock(sc->sc_hwmtx);
594248843Sadrian	return (ipend);
595248843Sadrian}
596248843Sadrian
597248843Sadrianstatic int
598248843Sadrianar933x_bus_param(struct uart_softc *sc, int baudrate, int databits,
599248843Sadrian    int stopbits, int parity)
600248843Sadrian{
601248843Sadrian	struct uart_bas *bas;
602248843Sadrian	int error;
603248843Sadrian
604248843Sadrian	bas = &sc->sc_bas;
605248843Sadrian	uart_lock(sc->sc_hwmtx);
606248843Sadrian	error = ar933x_param(bas, baudrate, databits, stopbits, parity);
607248843Sadrian	uart_unlock(sc->sc_hwmtx);
608248843Sadrian	return (error);
609248843Sadrian}
610248843Sadrian
611248843Sadrianstatic int
612248843Sadrianar933x_bus_probe(struct uart_softc *sc)
613248843Sadrian{
614248843Sadrian	struct uart_bas *bas;
615249093Sadrian	int error;
616248843Sadrian
617248843Sadrian	bas = &sc->sc_bas;
618248843Sadrian
619248843Sadrian	error = ar933x_probe(bas);
620248843Sadrian	if (error)
621248843Sadrian		return (error);
622248843Sadrian
623248843Sadrian	/* Reset FIFOs. */
624249093Sadrian	ar933x_drain(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER);
625248843Sadrian
626249093Sadrian	/* XXX TODO: actually find out what the FIFO depth is! */
627249093Sadrian	sc->sc_rxfifosz = 16;
628248843Sadrian	sc->sc_txfifosz = 16;
629248843Sadrian
630248843Sadrian	return (0);
631248843Sadrian}
632248843Sadrian
633248843Sadrianstatic int
634248843Sadrianar933x_bus_receive(struct uart_softc *sc)
635248843Sadrian{
636249093Sadrian	struct uart_bas *bas = &sc->sc_bas;
637248843Sadrian	int xc;
638248843Sadrian
639248843Sadrian	uart_lock(sc->sc_hwmtx);
640249093Sadrian
641249093Sadrian	/* Loop over until we are full, or no data is available */
642249093Sadrian	while (ar933x_rxready(bas)) {
643248843Sadrian		if (uart_rx_full(sc)) {
644248843Sadrian			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
645248843Sadrian			break;
646248843Sadrian		}
647249093Sadrian
648249093Sadrian		/* Read the top of the RX FIFO */
649249093Sadrian		xc = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff;
650249093Sadrian
651249093Sadrian		/* Remove that entry from said RX FIFO */
652249093Sadrian		ar933x_setreg(bas, AR933X_UART_DATA_REG,
653249093Sadrian		    AR933X_UART_DATA_RX_CSR);
654249120Sadrian		uart_barrier(bas);
655249093Sadrian
656249093Sadrian		/* XXX frame, parity error */
657248843Sadrian		uart_rx_put(sc, xc);
658248843Sadrian	}
659249093Sadrian
660249093Sadrian	/*
661249093Sadrian	 * XXX TODO: Discard everything left in the Rx FIFO?
662249093Sadrian	 * XXX only if we've hit an overrun condition?
663249093Sadrian	 */
664249093Sadrian
665248843Sadrian	uart_unlock(sc->sc_hwmtx);
666249093Sadrian
667248843Sadrian	return (0);
668248843Sadrian}
669248843Sadrian
670248843Sadrianstatic int
671248843Sadrianar933x_bus_setsig(struct uart_softc *sc, int sig)
672248843Sadrian{
673248843Sadrian#if 0
674248843Sadrian	struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc;
675248843Sadrian	struct uart_bas *bas;
676248843Sadrian	uint32_t new, old;
677248843Sadrian
678248843Sadrian	bas = &sc->sc_bas;
679248843Sadrian	do {
680248843Sadrian		old = sc->sc_hwsig;
681248843Sadrian		new = old;
682248843Sadrian		if (sig & SER_DDTR) {
683248843Sadrian			SIGCHG(sig & SER_DTR, new, SER_DTR,
684248843Sadrian			    SER_DDTR);
685248843Sadrian		}
686248843Sadrian		if (sig & SER_DRTS) {
687248843Sadrian			SIGCHG(sig & SER_RTS, new, SER_RTS,
688248843Sadrian			    SER_DRTS);
689248843Sadrian		}
690248843Sadrian	} while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
691248843Sadrian	uart_lock(sc->sc_hwmtx);
692248843Sadrian	ns8250->mcr &= ~(MCR_DTR|MCR_RTS);
693248843Sadrian	if (new & SER_DTR)
694248843Sadrian		ns8250->mcr |= MCR_DTR;
695248843Sadrian	if (new & SER_RTS)
696248843Sadrian		ns8250->mcr |= MCR_RTS;
697248843Sadrian	uart_setreg(bas, REG_MCR, ns8250->mcr);
698248843Sadrian	uart_barrier(bas);
699248843Sadrian	uart_unlock(sc->sc_hwmtx);
700248843Sadrian#endif
701248843Sadrian	return (0);
702248843Sadrian}
703248843Sadrian
704249120Sadrian/*
705249120Sadrian * Write the current transmit buffer to the TX FIFO.
706249120Sadrian *
707249120Sadrian * Unfortunately the FreeBSD uart device has no concept of
708249120Sadrian * partial UART writes - it expects that the whole buffer
709249120Sadrian * is written to the hardware.  Thus for now, this will wait for
710249120Sadrian * the FIFO to finish draining before it pushes more frames into it.
711249120Sadrian *
712249120Sadrian * If non-blocking operation is truely needed here, either
713249120Sadrian * the FreeBSD uart device will need to handle partial writes
714249120Sadrian * in xxx_bus_transmit(), or we'll need to do TX FIFO buffering
715249120Sadrian * of our own here.
716249120Sadrian */
717248843Sadrianstatic int
718248843Sadrianar933x_bus_transmit(struct uart_softc *sc)
719248843Sadrian{
720249093Sadrian	struct uart_bas *bas = &sc->sc_bas;
721249120Sadrian	struct ar933x_softc *u = (struct ar933x_softc *)sc;
722248843Sadrian	int i;
723248843Sadrian
724248843Sadrian	uart_lock(sc->sc_hwmtx);
725249093Sadrian
726249120Sadrian	/* Wait for the FIFO to be clear - see above */
727249120Sadrian	while (ar933x_getreg(bas, AR933X_UART_CS_REG) &
728249120Sadrian	    AR933X_UART_CS_TX_BUSY)
729249120Sadrian		;
730249093Sadrian
731249120Sadrian	/*
732249120Sadrian	 * Write some data!
733249120Sadrian	 */
734248843Sadrian	for (i = 0; i < sc->sc_txdatasz; i++) {
735249093Sadrian		/* Write the TX data */
736249093Sadrian		ar933x_setreg(bas, AR933X_UART_DATA_REG,
737249093Sadrian		    (sc->sc_txbuf[i] & 0xff) | AR933X_UART_DATA_TX_CSR);
738249120Sadrian		uart_barrier(bas);
739248843Sadrian	}
740249093Sadrian
741249093Sadrian	/*
742249120Sadrian	 * Now that we're transmitting, get interrupt notification
743249120Sadrian	 * when the FIFO is (almost) empty - see above.
744249120Sadrian	 */
745249120Sadrian	u->u_ier |= AR933X_UART_INT_TX_EMPTY;
746249120Sadrian	ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier);
747249120Sadrian	uart_barrier(bas);
748249120Sadrian
749249120Sadrian	/*
750249093Sadrian	 * Inform the upper layer that we are presently transmitting
751249093Sadrian	 * data to the hardware; this will be cleared when the
752249093Sadrian	 * TXIDLE interrupt occurs.
753249093Sadrian	 */
754248843Sadrian	sc->sc_txbusy = 1;
755248843Sadrian	uart_unlock(sc->sc_hwmtx);
756249093Sadrian
757248843Sadrian	return (0);
758248843Sadrian}
759262649Simp
760262649Simpstatic void
761262649Simpar933x_bus_grab(struct uart_softc *sc)
762262649Simp{
763262649Simp	struct uart_bas *bas = &sc->sc_bas;
764262649Simp	uint32_t reg;
765262649Simp
766262649Simp	/* Disable the host interrupt now */
767262649Simp	uart_lock(sc->sc_hwmtx);
768262649Simp	reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
769262649Simp	reg &= ~AR933X_UART_CS_HOST_INT_EN;
770262649Simp	ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
771262649Simp	uart_unlock(sc->sc_hwmtx);
772262649Simp}
773262649Simp
774262649Simpstatic void
775262649Simpar933x_bus_ungrab(struct uart_softc *sc)
776262649Simp{
777262649Simp	struct uart_bas *bas = &sc->sc_bas;
778262649Simp	uint32_t reg;
779262649Simp
780262649Simp	/* Enable the host interrupt now */
781262649Simp	uart_lock(sc->sc_hwmtx);
782262649Simp	reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
783262649Simp	reg |= AR933X_UART_CS_HOST_INT_EN;
784262649Simp	ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
785262649Simp	uart_unlock(sc->sc_hwmtx);
786262649Simp}
787