1139749Simp/*-
2119815Smarcel * Copyright (c) 2003 Marcel Moolenaar
3119815Smarcel * All rights reserved.
4119815Smarcel *
5119815Smarcel * Redistribution and use in source and binary forms, with or without
6119815Smarcel * modification, are permitted provided that the following conditions
7119815Smarcel * are met:
8119815Smarcel *
9119815Smarcel * 1. Redistributions of source code must retain the above copyright
10119815Smarcel *    notice, this list of conditions and the following disclaimer.
11119815Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12119815Smarcel *    notice, this list of conditions and the following disclaimer in the
13119815Smarcel *    documentation and/or other materials provided with the distribution.
14119815Smarcel *
15119815Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16119815Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17119815Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18119815Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19119815Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20119815Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21119815Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22119815Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23119815Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24119815Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25119815Smarcel */
26119815Smarcel
27119815Smarcel#include <sys/cdefs.h>
28119815Smarcel__FBSDID("$FreeBSD: stable/11/sys/dev/uart/uart_core.c 365480 2020-09-08 22:50:24Z jhb $");
29119815Smarcel
30119815Smarcel#include <sys/param.h>
31119815Smarcel#include <sys/systm.h>
32119815Smarcel#include <sys/bus.h>
33119815Smarcel#include <sys/conf.h>
34119815Smarcel#include <sys/cons.h>
35119815Smarcel#include <sys/fcntl.h>
36119815Smarcel#include <sys/interrupt.h>
37131921Smarcel#include <sys/kdb.h>
38119815Smarcel#include <sys/kernel.h>
39119815Smarcel#include <sys/malloc.h>
40119815Smarcel#include <sys/queue.h>
41119815Smarcel#include <sys/reboot.h>
42285619Sneel#include <sys/sysctl.h>
43119815Smarcel#include <machine/bus.h>
44119815Smarcel#include <sys/rman.h>
45119815Smarcel#include <machine/resource.h>
46119815Smarcel#include <machine/stdarg.h>
47119815Smarcel
48119815Smarcel#include <dev/uart/uart.h>
49119815Smarcel#include <dev/uart/uart_bus.h>
50119815Smarcel#include <dev/uart/uart_cpu.h>
51293781Sian#include <dev/uart/uart_ppstypes.h>
52119815Smarcel
53119815Smarcel#include "uart_if.h"
54119815Smarcel
55119815Smarceldevclass_t uart_devclass;
56285843Smariusconst char uart_driver_name[] = "uart";
57119815Smarcel
58119815SmarcelSLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs =
59119815Smarcel    SLIST_HEAD_INITIALIZER(uart_sysdevs);
60119815Smarcel
61227293Sedstatic MALLOC_DEFINE(M_UART, "UART", "UART driver");
62119815Smarcel
63234194Sgrehan#ifndef	UART_POLL_FREQ
64234194Sgrehan#define	UART_POLL_FREQ		50
65234194Sgrehan#endif
66234194Sgrehanstatic int uart_poll_freq = UART_POLL_FREQ;
67285619SneelSYSCTL_INT(_debug, OID_AUTO, uart_poll_freq, CTLFLAG_RDTUN, &uart_poll_freq,
68285619Sneel    0, "UART poll frequency");
69234194Sgrehan
70285619Sneelstatic int uart_force_poll;
71285619SneelSYSCTL_INT(_debug, OID_AUTO, uart_force_poll, CTLFLAG_RDTUN, &uart_force_poll,
72285619Sneel    0, "Force UART polling");
73285619Sneel
74286591Sianstatic inline int
75293781Sianuart_pps_mode_valid(int pps_mode)
76286591Sian{
77293781Sian	int opt;
78286591Sian
79293781Sian	switch(pps_mode & UART_PPS_SIGNAL_MASK) {
80293781Sian	case UART_PPS_DISABLED:
81293781Sian	case UART_PPS_CTS:
82293781Sian	case UART_PPS_DCD:
83293781Sian		break;
84293781Sian	default:
85293781Sian		return (false);
86286591Sian	}
87286591Sian
88293781Sian	opt = pps_mode & UART_PPS_OPTION_MASK;
89293781Sian	if ((opt & ~(UART_PPS_INVERT_PULSE | UART_PPS_NARROW_PULSE)) != 0)
90293781Sian		return (false);
91293781Sian
92293781Sian	return (true);
93286591Sian}
94286591Sian
95293781Sianstatic void
96293781Sianuart_pps_print_mode(struct uart_softc *sc)
97286591Sian{
98293781Sian
99293781Sian	device_printf(sc->sc_dev, "PPS capture mode: ");
100293781Sian	switch(sc->sc_pps_mode) {
101293781Sian	case UART_PPS_DISABLED:
102293781Sian		printf("disabled");
103293781Sian	case UART_PPS_CTS:
104293781Sian		printf("CTS");
105293781Sian	case UART_PPS_DCD:
106293781Sian		printf("DCD");
107293781Sian	default:
108293781Sian		printf("invalid");
109286591Sian	}
110293781Sian	if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE)
111293781Sian		printf("-Inverted");
112293781Sian	if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE)
113293781Sian		printf("-NarrowPulse");
114293781Sian	printf("\n");
115286591Sian}
116286591Sian
117286591Sianstatic int
118286591Sianuart_pps_mode_sysctl(SYSCTL_HANDLER_ARGS)
119286591Sian{
120286591Sian	struct uart_softc *sc;
121286591Sian	int err, tmp;
122286591Sian
123286591Sian	sc = arg1;
124286591Sian	tmp = sc->sc_pps_mode;
125286591Sian	err = sysctl_handle_int(oidp, &tmp, 0, req);
126286591Sian	if (err != 0 || req->newptr == NULL)
127286591Sian		return (err);
128286591Sian	if (!uart_pps_mode_valid(tmp))
129286591Sian		return (EINVAL);
130286591Sian	sc->sc_pps_mode = tmp;
131286591Sian	return(0);
132286591Sian}
133286591Sian
134286591Sianstatic void
135293781Sianuart_pps_process(struct uart_softc *sc, int ser_sig)
136293781Sian{
137293781Sian	sbintime_t now;
138293781Sian	int is_assert, pps_sig;
139293781Sian
140293781Sian	/* Which signal is configured as PPS?  Early out if none. */
141293781Sian	switch(sc->sc_pps_mode & UART_PPS_SIGNAL_MASK) {
142293781Sian	case UART_PPS_CTS:
143293781Sian		pps_sig = SER_CTS;
144293781Sian		break;
145293781Sian	case UART_PPS_DCD:
146293781Sian		pps_sig = SER_DCD;
147293781Sian		break;
148293781Sian	default:
149293781Sian		return;
150293781Sian	}
151293781Sian
152293781Sian	/* Early out if there is no change in the signal configured as PPS. */
153293781Sian	if ((ser_sig & SER_DELTA(pps_sig)) == 0)
154293781Sian		return;
155293781Sian
156293781Sian	/*
157293781Sian	 * In narrow-pulse mode we need to synthesize both capture and clear
158293781Sian	 * events from a single "delta occurred" indication from the uart
159293781Sian	 * hardware because the pulse width is too narrow to reliably detect
160293781Sian	 * both edges.  However, when the pulse width is close to our interrupt
161293781Sian	 * processing latency we might intermittantly catch both edges.  To
162293781Sian	 * guard against generating spurious events when that happens, we use a
163293781Sian	 * separate timer to ensure at least half a second elapses before we
164293781Sian	 * generate another event.
165293781Sian	 */
166293781Sian	pps_capture(&sc->sc_pps);
167293781Sian	if (sc->sc_pps_mode & UART_PPS_NARROW_PULSE) {
168293781Sian		now = getsbinuptime();
169293781Sian		if (now > sc->sc_pps_captime + 500 * SBT_1MS) {
170293781Sian			sc->sc_pps_captime = now;
171293781Sian			pps_event(&sc->sc_pps, PPS_CAPTUREASSERT);
172293781Sian			pps_event(&sc->sc_pps, PPS_CAPTURECLEAR);
173293781Sian		}
174293781Sian	} else  {
175293781Sian		is_assert = ser_sig & pps_sig;
176293781Sian		if (sc->sc_pps_mode & UART_PPS_INVERT_PULSE)
177293781Sian			is_assert = !is_assert;
178293781Sian		pps_event(&sc->sc_pps, is_assert ? PPS_CAPTUREASSERT :
179293781Sian		    PPS_CAPTURECLEAR);
180293781Sian	}
181293781Sian}
182293781Sian
183293781Sianstatic void
184286591Sianuart_pps_init(struct uart_softc *sc)
185286591Sian{
186286591Sian	struct sysctl_ctx_list *ctx;
187286591Sian	struct sysctl_oid *tree;
188286591Sian
189286591Sian	ctx = device_get_sysctl_ctx(sc->sc_dev);
190286591Sian	tree = device_get_sysctl_tree(sc->sc_dev);
191286591Sian
192286591Sian	/*
193286591Sian	 * The historical default for pps capture mode is either DCD or CTS,
194286591Sian	 * depending on the UART_PPS_ON_CTS kernel option.  Start with that,
195286591Sian	 * then try to fetch the tunable that overrides the mode for all uart
196286591Sian	 * devices, then try to fetch the sysctl-tunable that overrides the mode
197286591Sian	 * for one specific device.
198286591Sian	 */
199286591Sian#ifdef UART_PPS_ON_CTS
200293781Sian	sc->sc_pps_mode = UART_PPS_CTS;
201286591Sian#else
202293781Sian	sc->sc_pps_mode = UART_PPS_DCD;
203286591Sian#endif
204286591Sian	TUNABLE_INT_FETCH("hw.uart.pps_mode", &sc->sc_pps_mode);
205286591Sian	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "pps_mode",
206286591Sian	    CTLTYPE_INT | CTLFLAG_RWTUN, sc, 0, uart_pps_mode_sysctl, "I",
207293781Sian	    "pulse mode: 0/1/2=disabled/CTS/DCD; "
208293781Sian	    "add 0x10 to invert, 0x20 for narrow pulse");
209286591Sian
210286591Sian	if (!uart_pps_mode_valid(sc->sc_pps_mode)) {
211286591Sian		device_printf(sc->sc_dev,
212293781Sian		    "Invalid pps_mode 0x%02x configured; disabling PPS capture\n",
213286591Sian		    sc->sc_pps_mode);
214293781Sian		sc->sc_pps_mode = UART_PPS_DISABLED;
215286591Sian	} else if (bootverbose) {
216293781Sian		uart_pps_print_mode(sc);
217286591Sian	}
218286591Sian
219286591Sian	sc->sc_pps.ppscap = PPS_CAPTUREBOTH;
220286591Sian	sc->sc_pps.driver_mtx = uart_tty_getlock(sc);
221286591Sian	sc->sc_pps.driver_abi = PPS_ABI_VERSION;
222286591Sian	pps_init_abi(&sc->sc_pps);
223286591Sian}
224286591Sian
225119815Smarcelvoid
226119815Smarceluart_add_sysdev(struct uart_devinfo *di)
227119815Smarcel{
228119815Smarcel	SLIST_INSERT_HEAD(&uart_sysdevs, di, next);
229119815Smarcel}
230119815Smarcel
231168281Smarcelconst char *
232168281Smarceluart_getname(struct uart_class *uc)
233168281Smarcel{
234168281Smarcel	return ((uc != NULL) ? uc->name : NULL);
235168281Smarcel}
236168281Smarcel
237168281Smarcelstruct uart_ops *
238168281Smarceluart_getops(struct uart_class *uc)
239168281Smarcel{
240168281Smarcel	return ((uc != NULL) ? uc->uc_ops : NULL);
241168281Smarcel}
242168281Smarcel
243168281Smarcelint
244168281Smarceluart_getrange(struct uart_class *uc)
245168281Smarcel{
246168281Smarcel	return ((uc != NULL) ? uc->uc_range : 0);
247168281Smarcel}
248168281Smarcel
249281438Sandrewu_int
250281438Sandrewuart_getregshift(struct uart_class *uc)
251281438Sandrew{
252281438Sandrew	return ((uc != NULL) ? uc->uc_rshift : 0);
253281438Sandrew}
254281438Sandrew
255340145Smmacyu_int
256340145Smmacyuart_getregiowidth(struct uart_class *uc)
257340145Smmacy{
258340145Smmacy	return ((uc != NULL) ? uc->uc_riowidth : 0);
259340145Smmacy}
260340145Smmacy
261119815Smarcel/*
262157300Smarcel * Schedule a soft interrupt. We do this on the 0 to !0 transition
263157300Smarcel * of the TTY pending interrupt status.
264157300Smarcel */
265197721Smarcelvoid
266157300Smarceluart_sched_softih(struct uart_softc *sc, uint32_t ipend)
267157300Smarcel{
268157300Smarcel	uint32_t new, old;
269157300Smarcel
270157300Smarcel	do {
271157300Smarcel		old = sc->sc_ttypend;
272157300Smarcel		new = old | ipend;
273157300Smarcel	} while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
274157300Smarcel
275157300Smarcel	if ((old & SER_INT_MASK) == 0)
276157300Smarcel		swi_sched(sc->sc_softih, 0);
277157300Smarcel}
278157300Smarcel
279157300Smarcel/*
280119815Smarcel * A break condition has been detected. We treat the break condition as
281119815Smarcel * a special case that should not happen during normal operation. When
282119815Smarcel * the break condition is to be passed to higher levels in the form of
283119815Smarcel * a NUL character, we really want the break to be in the right place in
284119815Smarcel * the input stream. The overhead to achieve that is not in relation to
285119815Smarcel * the exceptional nature of the break condition, so we permit ourselves
286119815Smarcel * to be sloppy.
287119815Smarcel */
288157300Smarcelstatic __inline int
289157300Smarceluart_intr_break(void *arg)
290119815Smarcel{
291157300Smarcel	struct uart_softc *sc = arg;
292119815Smarcel
293225203Srwatson#if defined(KDB)
294119815Smarcel	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
295225203Srwatson		if (kdb_break())
296225203Srwatson			return (0);
297119815Smarcel	}
298119815Smarcel#endif
299119815Smarcel	if (sc->sc_opened)
300157300Smarcel		uart_sched_softih(sc, SER_INT_BREAK);
301157300Smarcel	return (0);
302119815Smarcel}
303119815Smarcel
304119815Smarcel/*
305119815Smarcel * Handle a receiver overrun situation. We lost at least 1 byte in the
306119815Smarcel * input stream and it's our job to contain the situation. We grab as
307119815Smarcel * much of the data we can, but otherwise flush the receiver FIFO to
308119815Smarcel * create some breathing room. The net effect is that we avoid the
309119815Smarcel * overrun condition to happen for the next X characters, where X is
310250576Seadler * related to the FIFO size at the cost of losing data right away.
311119815Smarcel * So, instead of having multiple overrun interrupts in close proximity
312119815Smarcel * to each other and possibly pessimizing UART interrupt latency for
313119815Smarcel * other UARTs in a multiport configuration, we create a longer segment
314119815Smarcel * of missing characters by freeing up the FIFO.
315119815Smarcel * Each overrun condition is marked in the input buffer by a token. The
316119815Smarcel * token represents the loss of at least one, but possible more bytes in
317119815Smarcel * the input stream.
318119815Smarcel */
319157300Smarcelstatic __inline int
320157300Smarceluart_intr_overrun(void *arg)
321119815Smarcel{
322157300Smarcel	struct uart_softc *sc = arg;
323119815Smarcel
324119815Smarcel	if (sc->sc_opened) {
325119815Smarcel		UART_RECEIVE(sc);
326119815Smarcel		if (uart_rx_put(sc, UART_STAT_OVERRUN))
327119815Smarcel			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
328157300Smarcel		uart_sched_softih(sc, SER_INT_RXREADY);
329119815Smarcel	}
330365480Sjhb	sc->sc_rxoverruns++;
331119815Smarcel	UART_FLUSH(sc, UART_FLUSH_RECEIVER);
332157300Smarcel	return (0);
333119815Smarcel}
334119815Smarcel
335119815Smarcel/*
336119815Smarcel * Received data ready.
337119815Smarcel */
338157300Smarcelstatic __inline int
339157300Smarceluart_intr_rxready(void *arg)
340119815Smarcel{
341157300Smarcel	struct uart_softc *sc = arg;
342119815Smarcel	int rxp;
343119815Smarcel
344119815Smarcel	rxp = sc->sc_rxput;
345119815Smarcel	UART_RECEIVE(sc);
346225203Srwatson#if defined(KDB)
347119815Smarcel	if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
348119815Smarcel		while (rxp != sc->sc_rxput) {
349225203Srwatson			kdb_alt_break(sc->sc_rxbuf[rxp++], &sc->sc_altbrk);
350119815Smarcel			if (rxp == sc->sc_rxbufsz)
351119815Smarcel				rxp = 0;
352119815Smarcel		}
353119815Smarcel	}
354119815Smarcel#endif
355119815Smarcel	if (sc->sc_opened)
356157300Smarcel		uart_sched_softih(sc, SER_INT_RXREADY);
357119815Smarcel	else
358119815Smarcel		sc->sc_rxput = sc->sc_rxget;	/* Ignore received data. */
359157300Smarcel	return (1);
360119815Smarcel}
361119815Smarcel
362119815Smarcel/*
363119815Smarcel * Line or modem status change (OOB signalling).
364119815Smarcel * We pass the signals to the software interrupt handler for further
365119815Smarcel * processing. Note that we merge the delta bits, but set the state
366250576Seadler * bits. This is to avoid losing state transitions due to having more
367119815Smarcel * than 1 hardware interrupt between software interrupts.
368119815Smarcel */
369157300Smarcelstatic __inline int
370157300Smarceluart_intr_sigchg(void *arg)
371119815Smarcel{
372157300Smarcel	struct uart_softc *sc = arg;
373293781Sian	int new, old, sig;
374119815Smarcel
375119815Smarcel	sig = UART_GETSIG(sc);
376119996Smarcel
377286595Sian	/*
378293781Sian	 * Time pulse counting support, invoked whenever the PPS parameters are
379293781Sian	 * currently set to capture either edge of the signal.
380286595Sian	 */
381119996Smarcel	if (sc->sc_pps.ppsparam.mode & PPS_CAPTUREBOTH) {
382293781Sian		uart_pps_process(sc, sig);
383119996Smarcel	}
384119996Smarcel
385157300Smarcel	/*
386157300Smarcel	 * Keep track of signal changes, even when the device is not
387157300Smarcel	 * opened. This allows us to inform upper layers about a
388157300Smarcel	 * possible loss of DCD and thus the existence of a (possibly)
389157300Smarcel	 * different connection when we have DCD back, during the time
390157300Smarcel	 * that the device was closed.
391157300Smarcel	 */
392119815Smarcel	do {
393119815Smarcel		old = sc->sc_ttypend;
394155973Smarcel		new = old & ~SER_MASK_STATE;
395155971Smarcel		new |= sig & SER_INT_SIGMASK;
396119815Smarcel	} while (!atomic_cmpset_32(&sc->sc_ttypend, old, new));
397157300Smarcel
398157300Smarcel	if (sc->sc_opened)
399157300Smarcel		uart_sched_softih(sc, SER_INT_SIGCHG);
400157300Smarcel	return (1);
401119815Smarcel}
402119815Smarcel
403119815Smarcel/*
404119815Smarcel * The transmitter can accept more data.
405119815Smarcel */
406157300Smarcelstatic __inline int
407157300Smarceluart_intr_txidle(void *arg)
408119815Smarcel{
409157300Smarcel	struct uart_softc *sc = arg;
410157300Smarcel
411119815Smarcel	if (sc->sc_txbusy) {
412119815Smarcel		sc->sc_txbusy = 0;
413157300Smarcel		uart_sched_softih(sc, SER_INT_TXIDLE);
414119815Smarcel	}
415157300Smarcel	return (0);
416119815Smarcel}
417119815Smarcel
418166901Spisostatic int
419119815Smarceluart_intr(void *arg)
420119815Smarcel{
421119815Smarcel	struct uart_softc *sc = arg;
422285843Smarius	int cnt, ipend, testintr;
423119815Smarcel
424253161Smarcel	if (sc->sc_leaving)
425253161Smarcel		return (FILTER_STRAY);
426253161Smarcel
427253161Smarcel	cnt = 0;
428285843Smarius	testintr = sc->sc_testintr;
429285843Smarius	while ((!testintr || cnt < 20) && (ipend = UART_IPEND(sc)) != 0) {
430253161Smarcel		cnt++;
431155971Smarcel		if (ipend & SER_INT_OVERRUN)
432120146Smarcel			uart_intr_overrun(sc);
433155971Smarcel		if (ipend & SER_INT_BREAK)
434120146Smarcel			uart_intr_break(sc);
435155971Smarcel		if (ipend & SER_INT_RXREADY)
436120146Smarcel			uart_intr_rxready(sc);
437155971Smarcel		if (ipend & SER_INT_SIGCHG)
438120146Smarcel			uart_intr_sigchg(sc);
439155971Smarcel		if (ipend & SER_INT_TXIDLE)
440285843Smarius			uart_intr_txidle(sc);
441157300Smarcel	}
442234194Sgrehan
443234194Sgrehan	if (sc->sc_polled) {
444234194Sgrehan		callout_reset(&sc->sc_timer, hz / uart_poll_freq,
445234194Sgrehan		    (timeout_t *)uart_intr, sc);
446234194Sgrehan	}
447234194Sgrehan
448253161Smarcel	return ((cnt == 0) ? FILTER_STRAY :
449285843Smarius	    ((testintr && cnt == 20) ? FILTER_SCHEDULE_THREAD :
450285843Smarius	    FILTER_HANDLED));
451157300Smarcel}
452119815Smarcel
453157300Smarcelserdev_intr_t *
454157300Smarceluart_bus_ihand(device_t dev, int ipend)
455157300Smarcel{
456157300Smarcel
457157300Smarcel	switch (ipend) {
458157300Smarcel	case SER_INT_BREAK:
459157300Smarcel		return (uart_intr_break);
460157300Smarcel	case SER_INT_OVERRUN:
461157300Smarcel		return (uart_intr_overrun);
462157300Smarcel	case SER_INT_RXREADY:
463157300Smarcel		return (uart_intr_rxready);
464157300Smarcel	case SER_INT_SIGCHG:
465157300Smarcel		return (uart_intr_sigchg);
466157300Smarcel	case SER_INT_TXIDLE:
467157300Smarcel		return (uart_intr_txidle);
468157300Smarcel	}
469157300Smarcel	return (NULL);
470119815Smarcel}
471119815Smarcel
472119815Smarcelint
473158119Smarceluart_bus_ipend(device_t dev)
474158119Smarcel{
475158119Smarcel	struct uart_softc *sc;
476158119Smarcel
477158119Smarcel	sc = device_get_softc(dev);
478158119Smarcel	return (UART_IPEND(sc));
479158119Smarcel}
480158119Smarcel
481158119Smarcelint
482157300Smarceluart_bus_sysdev(device_t dev)
483157300Smarcel{
484157300Smarcel	struct uart_softc *sc;
485157300Smarcel
486157300Smarcel	sc = device_get_softc(dev);
487157300Smarcel	return ((sc->sc_sysdev != NULL) ? 1 : 0);
488157300Smarcel}
489157300Smarcel
490157300Smarcelint
491340145Smmacyuart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int chan, int quirks)
492119815Smarcel{
493119815Smarcel	struct uart_softc *sc;
494119815Smarcel	struct uart_devinfo *sysdev;
495119815Smarcel	int error;
496119815Smarcel
497168281Smarcel	sc = device_get_softc(dev);
498168281Smarcel
499119815Smarcel	/*
500168281Smarcel	 * All uart_class references are weak. Check that the needed
501168281Smarcel	 * class has been compiled-in. Fail if not.
502168281Smarcel	 */
503168281Smarcel	if (sc->sc_class == NULL)
504168281Smarcel		return (ENXIO);
505168281Smarcel
506168281Smarcel	/*
507119815Smarcel	 * Initialize the instance. Note that the instance (=softc) does
508119815Smarcel	 * not necessarily match the hardware specific softc. We can't do
509119815Smarcel	 * anything about it now, because we may not attach to the device.
510119815Smarcel	 * Hardware drivers cannot use any of the class specific fields
511119815Smarcel	 * while probing.
512119815Smarcel	 */
513119815Smarcel	kobj_init((kobj_t)sc, (kobj_class_t)sc->sc_class);
514119815Smarcel	sc->sc_dev = dev;
515119815Smarcel	if (device_get_desc(dev) == NULL)
516168281Smarcel		device_set_desc(dev, uart_getname(sc->sc_class));
517119815Smarcel
518119815Smarcel	/*
519119815Smarcel	 * Allocate the register resource. We assume that all UARTs have
520119815Smarcel	 * a single register window in either I/O port space or memory
521119815Smarcel	 * mapped I/O space. Any UART that needs multiple windows will
522119815Smarcel	 * consequently not be supported by this driver as-is. We try I/O
523119815Smarcel	 * port space first because that's the common case.
524119815Smarcel	 */
525119815Smarcel	sc->sc_rrid = rid;
526119815Smarcel	sc->sc_rtype = SYS_RES_IOPORT;
527286653Smarcel	sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
528286653Smarcel	    RF_ACTIVE);
529119815Smarcel	if (sc->sc_rres == NULL) {
530119815Smarcel		sc->sc_rrid = rid;
531119815Smarcel		sc->sc_rtype = SYS_RES_MEMORY;
532286653Smarcel		sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype,
533286653Smarcel		    &sc->sc_rrid, RF_ACTIVE);
534119815Smarcel		if (sc->sc_rres == NULL)
535119815Smarcel			return (ENXIO);
536119815Smarcel	}
537119815Smarcel
538119815Smarcel	/*
539119815Smarcel	 * Fill in the bus access structure and compare this device with
540119815Smarcel	 * a possible console device and/or a debug port. We set the flags
541119815Smarcel	 * in the softc so that the hardware dependent probe can adjust
542119815Smarcel	 * accordingly. In general, you don't want to permanently disrupt
543119815Smarcel	 * console I/O.
544119815Smarcel	 */
545119815Smarcel	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
546119815Smarcel	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
547120452Smarcel	sc->sc_bas.chan = chan;
548119815Smarcel	sc->sc_bas.regshft = regshft;
549340145Smmacy	sc->sc_bas.regiowidth = regiowidth;
550119815Smarcel	sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk;
551340145Smmacy	sc->sc_bas.busy_detect = !!(quirks & UART_F_BUSY_DETECT);
552119815Smarcel
553119815Smarcel	SLIST_FOREACH(sysdev, &uart_sysdevs, next) {
554120452Smarcel		if (chan == sysdev->bas.chan &&
555120452Smarcel		    uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) {
556119815Smarcel			/* XXX check if ops matches class. */
557119815Smarcel			sc->sc_sysdev = sysdev;
558167999Smarcel			sysdev->bas.rclk = sc->sc_bas.rclk;
559119815Smarcel		}
560119815Smarcel	}
561119815Smarcel
562119815Smarcel	error = UART_PROBE(sc);
563119815Smarcel	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
564151792Smarcel	return ((error) ? error : BUS_PROBE_DEFAULT);
565119815Smarcel}
566119815Smarcel
567119815Smarcelint
568119815Smarceluart_bus_attach(device_t dev)
569119815Smarcel{
570119815Smarcel	struct uart_softc *sc, *sc0;
571119815Smarcel	const char *sep;
572253161Smarcel	int error, filt;
573119815Smarcel
574119815Smarcel	/*
575119815Smarcel	 * The sc_class field defines the type of UART we're going to work
576119815Smarcel	 * with and thus the size of the softc. Replace the generic softc
577119815Smarcel	 * with one that matches the UART now that we're certain we handle
578119815Smarcel	 * the device.
579119815Smarcel	 */
580119815Smarcel	sc0 = device_get_softc(dev);
581119815Smarcel	if (sc0->sc_class->size > sizeof(*sc)) {
582119815Smarcel		sc = malloc(sc0->sc_class->size, M_UART, M_WAITOK|M_ZERO);
583119815Smarcel		bcopy(sc0, sc, sizeof(*sc));
584119815Smarcel		device_set_softc(dev, sc);
585119815Smarcel	} else
586119815Smarcel		sc = sc0;
587119815Smarcel
588119815Smarcel	/*
589260890Simp	 * Now that we know the softc for this device, connect the back
590260890Simp	 * pointer from the sysdev for this device, if any
591260890Simp	 */
592260890Simp	if (sc->sc_sysdev != NULL)
593260890Simp		sc->sc_sysdev->sc = sc;
594260890Simp
595260890Simp	/*
596119815Smarcel	 * Protect ourselves against interrupts while we're not completely
597119815Smarcel	 * finished attaching and initializing. We don't expect interrupts
598285843Smarius	 * until after UART_ATTACH(), though.
599119815Smarcel	 */
600119815Smarcel	sc->sc_leaving = 1;
601119815Smarcel
602157300Smarcel	mtx_init(&sc->sc_hwmtx_s, "uart_hwmtx", NULL, MTX_SPIN);
603157300Smarcel	if (sc->sc_hwmtx == NULL)
604157300Smarcel		sc->sc_hwmtx = &sc->sc_hwmtx_s;
605120143Smarcel
606119815Smarcel	/*
607119815Smarcel	 * Re-allocate. We expect that the softc contains the information
608119815Smarcel	 * collected by uart_bus_probe() intact.
609119815Smarcel	 */
610286653Smarcel	sc->sc_rres = bus_alloc_resource_any(dev, sc->sc_rtype, &sc->sc_rrid,
611286653Smarcel	    RF_ACTIVE);
612143025Smarius	if (sc->sc_rres == NULL) {
613157300Smarcel		mtx_destroy(&sc->sc_hwmtx_s);
614119815Smarcel		return (ENXIO);
615143025Smarius	}
616120380Snyan	sc->sc_bas.bsh = rman_get_bushandle(sc->sc_rres);
617120380Snyan	sc->sc_bas.bst = rman_get_bustag(sc->sc_rres);
618120380Snyan
619248963Sian	/*
620248963Sian	 * Ensure there is room for at least three full FIFOs of data in the
621248963Sian	 * receive buffer (handles the case of low-level drivers with huge
622248963Sian	 * FIFOs), and also ensure that there is no less than the historical
623248963Sian	 * size of 384 bytes (handles the typical small-FIFO case).
624248963Sian	 */
625248963Sian	sc->sc_rxbufsz = MAX(384, sc->sc_rxfifosz * 3);
626119815Smarcel	sc->sc_rxbuf = malloc(sc->sc_rxbufsz * sizeof(*sc->sc_rxbuf),
627119815Smarcel	    M_UART, M_WAITOK);
628119815Smarcel	sc->sc_txbuf = malloc(sc->sc_txfifosz * sizeof(*sc->sc_txbuf),
629119815Smarcel	    M_UART, M_WAITOK);
630119815Smarcel
631119815Smarcel	error = UART_ATTACH(sc);
632119815Smarcel	if (error)
633119815Smarcel		goto fail;
634119815Smarcel
635119815Smarcel	if (sc->sc_hwiflow || sc->sc_hwoflow) {
636119815Smarcel		sep = "";
637119815Smarcel		device_print_prettyname(dev);
638119815Smarcel		if (sc->sc_hwiflow) {
639119815Smarcel			printf("%sRTS iflow", sep);
640119815Smarcel			sep = ", ";
641119815Smarcel		}
642119815Smarcel		if (sc->sc_hwoflow) {
643119815Smarcel			printf("%sCTS oflow", sep);
644119815Smarcel			sep = ", ";
645119815Smarcel		}
646119815Smarcel		printf("\n");
647119815Smarcel	}
648119815Smarcel
649119815Smarcel	if (sc->sc_sysdev != NULL) {
650262932Simp		if (sc->sc_sysdev->baudrate == 0) {
651137706Smarcel			if (UART_IOCTL(sc, UART_IOCTL_BAUD,
652137706Smarcel			    (intptr_t)&sc->sc_sysdev->baudrate) != 0)
653137706Smarcel				sc->sc_sysdev->baudrate = -1;
654137706Smarcel		}
655119815Smarcel		switch (sc->sc_sysdev->type) {
656119815Smarcel		case UART_DEV_CONSOLE:
657119815Smarcel			device_printf(dev, "console");
658119815Smarcel			break;
659119815Smarcel		case UART_DEV_DBGPORT:
660119815Smarcel			device_printf(dev, "debug port");
661119815Smarcel			break;
662119815Smarcel		case UART_DEV_KEYBOARD:
663119815Smarcel			device_printf(dev, "keyboard");
664119815Smarcel			break;
665119815Smarcel		default:
666119815Smarcel			device_printf(dev, "unknown system device");
667119815Smarcel			break;
668119815Smarcel		}
669119815Smarcel		printf(" (%d,%c,%d,%d)\n", sc->sc_sysdev->baudrate,
670119815Smarcel		    "noems"[sc->sc_sysdev->parity], sc->sc_sysdev->databits,
671119815Smarcel		    sc->sc_sysdev->stopbits);
672119815Smarcel	}
673119815Smarcel
674253161Smarcel	sc->sc_leaving = 0;
675285843Smarius	sc->sc_testintr = 1;
676253161Smarcel	filt = uart_intr(sc);
677285843Smarius	sc->sc_testintr = 0;
678253161Smarcel
679253161Smarcel	/*
680253161Smarcel	 * Don't use interrupts if we couldn't clear any pending interrupt
681253161Smarcel	 * conditions. We may have broken H/W and polling is probably the
682253161Smarcel	 * safest thing to do.
683253161Smarcel	 */
684285619Sneel	if (filt != FILTER_SCHEDULE_THREAD && !uart_force_poll) {
685253161Smarcel		sc->sc_irid = 0;
686253161Smarcel		sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
687253161Smarcel		    &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE);
688253161Smarcel	}
689253161Smarcel	if (sc->sc_ires != NULL) {
690253161Smarcel		error = bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_TTY,
691253161Smarcel		    uart_intr, NULL, sc, &sc->sc_icookie);
692253161Smarcel		sc->sc_fastintr = (error == 0) ? 1 : 0;
693253161Smarcel
694253161Smarcel		if (!sc->sc_fastintr)
695253161Smarcel			error = bus_setup_intr(dev, sc->sc_ires,
696253161Smarcel			    INTR_TYPE_TTY | INTR_MPSAFE, NULL,
697253161Smarcel			    (driver_intr_t *)uart_intr, sc, &sc->sc_icookie);
698253161Smarcel
699253161Smarcel		if (error) {
700253161Smarcel			device_printf(dev, "could not activate interrupt\n");
701253161Smarcel			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
702253161Smarcel			    sc->sc_ires);
703253161Smarcel			sc->sc_ires = NULL;
704253161Smarcel		}
705253161Smarcel	}
706253161Smarcel	if (sc->sc_ires == NULL) {
707253161Smarcel		/* No interrupt resource. Force polled mode. */
708253161Smarcel		sc->sc_polled = 1;
709253161Smarcel		callout_init(&sc->sc_timer, 1);
710285619Sneel		callout_reset(&sc->sc_timer, hz / uart_poll_freq,
711285619Sneel		    (timeout_t *)uart_intr, sc);
712253161Smarcel	}
713253161Smarcel
714253161Smarcel	if (bootverbose && (sc->sc_fastintr || sc->sc_polled)) {
715253161Smarcel		sep = "";
716253161Smarcel		device_print_prettyname(dev);
717253161Smarcel		if (sc->sc_fastintr) {
718253161Smarcel			printf("%sfast interrupt", sep);
719253161Smarcel			sep = ", ";
720253161Smarcel		}
721253161Smarcel		if (sc->sc_polled) {
722254534Sian			printf("%spolled mode (%dHz)", sep, uart_poll_freq);
723253161Smarcel			sep = ", ";
724253161Smarcel		}
725253161Smarcel		printf("\n");
726253161Smarcel	}
727253161Smarcel
728286469Sian	if (sc->sc_sysdev != NULL && sc->sc_sysdev->attach != NULL) {
729286469Sian		if ((error = sc->sc_sysdev->attach(sc)) != 0)
730286469Sian			goto fail;
731286469Sian	} else {
732286469Sian		if ((error = uart_tty_attach(sc)) != 0)
733286469Sian			goto fail;
734286591Sian		uart_pps_init(sc);
735286469Sian	}
736119815Smarcel
737157300Smarcel	if (sc->sc_sysdev != NULL)
738157300Smarcel		sc->sc_sysdev->hwmtx = sc->sc_hwmtx;
739157300Smarcel
740365480Sjhb	if (sc->sc_rxfifosz > 1)
741365480Sjhb		SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
742365480Sjhb		    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
743365480Sjhb		    "rx_overruns", CTLFLAG_RD, &sc->sc_rxoverruns, 0,
744365480Sjhb		    "Receive overruns");
745365480Sjhb
746119815Smarcel	return (0);
747119815Smarcel
748119815Smarcel fail:
749119815Smarcel	free(sc->sc_txbuf, M_UART);
750119815Smarcel	free(sc->sc_rxbuf, M_UART);
751119815Smarcel
752119815Smarcel	if (sc->sc_ires != NULL) {
753119815Smarcel		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
754119815Smarcel		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
755119815Smarcel		    sc->sc_ires);
756119815Smarcel	}
757119815Smarcel	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
758119815Smarcel
759157300Smarcel	mtx_destroy(&sc->sc_hwmtx_s);
760143025Smarius
761119815Smarcel	return (error);
762119815Smarcel}
763119815Smarcel
764119815Smarcelint
765119815Smarceluart_bus_detach(device_t dev)
766119815Smarcel{
767119815Smarcel	struct uart_softc *sc;
768119815Smarcel
769119815Smarcel	sc = device_get_softc(dev);
770119815Smarcel
771119815Smarcel	sc->sc_leaving = 1;
772119815Smarcel
773157300Smarcel	if (sc->sc_sysdev != NULL)
774157300Smarcel		sc->sc_sysdev->hwmtx = NULL;
775157300Smarcel
776119815Smarcel	UART_DETACH(sc);
777119815Smarcel
778119815Smarcel	if (sc->sc_sysdev != NULL && sc->sc_sysdev->detach != NULL)
779119815Smarcel		(*sc->sc_sysdev->detach)(sc);
780119815Smarcel	else
781119815Smarcel		uart_tty_detach(sc);
782119815Smarcel
783119815Smarcel	free(sc->sc_txbuf, M_UART);
784119815Smarcel	free(sc->sc_rxbuf, M_UART);
785119815Smarcel
786119815Smarcel	if (sc->sc_ires != NULL) {
787119815Smarcel		bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie);
788119815Smarcel		bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
789119815Smarcel		    sc->sc_ires);
790119815Smarcel	}
791119815Smarcel	bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres);
792119815Smarcel
793157300Smarcel	mtx_destroy(&sc->sc_hwmtx_s);
794143025Smarius
795119815Smarcel	if (sc->sc_class->size > sizeof(*sc)) {
796119815Smarcel		device_set_softc(dev, NULL);
797119815Smarcel		free(sc, M_UART);
798119815Smarcel	} else
799119815Smarcel		device_set_softc(dev, NULL);
800119815Smarcel
801119815Smarcel	return (0);
802119815Smarcel}
803246243Savg
804246243Savgint
805246243Savguart_bus_resume(device_t dev)
806246243Savg{
807246243Savg	struct uart_softc *sc;
808246243Savg
809246243Savg	sc = device_get_softc(dev);
810246243Savg	return (UART_ATTACH(sc));
811246243Savg}
812260890Simp
813260890Simpvoid
814260890Simpuart_grab(struct uart_devinfo *di)
815260890Simp{
816260890Simp
817260890Simp	if (di->sc)
818260890Simp		UART_GRAB(di->sc);
819260890Simp}
820260890Simp
821260890Simpvoid
822260890Simpuart_ungrab(struct uart_devinfo *di)
823260890Simp{
824260890Simp
825260890Simp	if (di->sc)
826260890Simp		UART_UNGRAB(di->sc);
827260890Simp}
828