2 * Copyright (c) 2011-2012 Robert N. M. Watson
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
37 #include <sys/endian.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/reboot.h>
47 #include <machine/bus.h>
49 #include <dev/altera/jtag_uart/altera_jtag_uart.h>
52 * If one of the Altera JTAG UARTs is currently the system console, register
55 static struct altera_jtag_uart_softc *aju_cons_sc;
57 static tsw_outwakeup_t aju_outwakeup;
58 static void aju_ac_callout(void *);
59 static void aju_io_callout(void *);
61 static struct ttydevsw aju_ttydevsw = {
62 .tsw_flags = TF_NOPREFIX,
63 .tsw_outwakeup = aju_outwakeup,
67 * When polling for the AC bit, the number of times we have to not see it
68 * before assuming JTAG has disappeared on us. By default, two seconds.
70 #define AJU_JTAG_MAXMISS 10
73 * Polling intervals for input/output and JTAG connection events.
75 #define AJU_IO_POLLINTERVAL (hz/100)
76 #define AJU_AC_POLLINTERVAL (hz/5)
79 * Low-level read and write register routines; the Altera UART is little
80 * endian, so we byte swap 32-bit reads and writes.
82 static inline uint32_t
83 aju_data_read(struct altera_jtag_uart_softc *sc)
86 return (le32toh(bus_read_4(sc->ajus_mem_res,
87 ALTERA_JTAG_UART_DATA_OFF)));
91 aju_data_write(struct altera_jtag_uart_softc *sc, uint32_t v)
94 bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_DATA_OFF, htole32(v));
97 static inline uint32_t
98 aju_control_read(struct altera_jtag_uart_softc *sc)
101 return (le32toh(bus_read_4(sc->ajus_mem_res,
102 ALTERA_JTAG_UART_CONTROL_OFF)));
106 aju_control_write(struct altera_jtag_uart_softc *sc, uint32_t v)
109 bus_write_4(sc->ajus_mem_res, ALTERA_JTAG_UART_CONTROL_OFF,
114 * Slightly higher-level routines aware of buffering and flow control.
117 aju_writable(struct altera_jtag_uart_softc *sc)
120 return ((aju_control_read(sc) &
121 ALTERA_JTAG_UART_CONTROL_WSPACE) != 0);
125 aju_readable(struct altera_jtag_uart_softc *sc)
131 if (*sc->ajus_buffer_validp)
133 v = aju_data_read(sc);
134 if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
135 *sc->ajus_buffer_validp = 1;
136 *sc->ajus_buffer_datap = (v & ALTERA_JTAG_UART_DATA_DATA);
143 aju_read(struct altera_jtag_uart_softc *sc)
148 while (!aju_readable(sc));
149 *sc->ajus_buffer_validp = 0;
150 return (*sc->ajus_buffer_datap);
154 * Routines for enabling and disabling interrupts for read and write.
157 aju_intr_readable_enable(struct altera_jtag_uart_softc *sc)
163 v = aju_control_read(sc);
164 v |= ALTERA_JTAG_UART_CONTROL_RE;
165 aju_control_write(sc, v);
169 aju_intr_writable_enable(struct altera_jtag_uart_softc *sc)
175 v = aju_control_read(sc);
176 v |= ALTERA_JTAG_UART_CONTROL_WE;
177 aju_control_write(sc, v);
181 aju_intr_writable_disable(struct altera_jtag_uart_softc *sc)
187 v = aju_control_read(sc);
188 v &= ~ALTERA_JTAG_UART_CONTROL_WE;
189 aju_control_write(sc, v);
193 aju_intr_disable(struct altera_jtag_uart_softc *sc)
199 v = aju_control_read(sc);
200 v &= ~(ALTERA_JTAG_UART_CONTROL_RE | ALTERA_JTAG_UART_CONTROL_WE);
201 aju_control_write(sc, v);
205 * The actual work of checking for, and handling, available reads. This is
206 * used in both polled and interrupt-driven modes, as JTAG UARTs may be hooked
207 * up with, or without, IRQs allocated.
210 aju_handle_input(struct altera_jtag_uart_softc *sc, struct tty *tp)
214 tty_lock_assert(tp, MA_OWNED);
217 while (aju_readable(sc)) {
221 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
222 kdb_alt_break(c, &sc->ajus_alt_break_state);
224 ttydisc_rint(tp, c, 0);
228 ttydisc_rint_done(tp);
233 * Send output to the UART until either there's none left to send, or we run
234 * out of room and need to await an interrupt so that we can start sending
237 * XXXRW: It would be nice to query WSPACE at the beginning and write to the
238 * FIFO in bugger chunks.
241 aju_handle_output(struct altera_jtag_uart_softc *sc, struct tty *tp)
246 tty_lock_assert(tp, MA_OWNED);
250 while (ttydisc_getc_poll(tp) != 0) {
252 v = aju_control_read(sc);
253 if ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) != 0) {
255 if (ttydisc_getc(tp, &ch, sizeof(ch)) != sizeof(ch))
256 panic("%s: ttydisc_getc", __func__);
260 * XXXRW: There is a slight race here in which we test
261 * for writability, drop the lock, get the character
262 * from the tty layer, re-acquire the lock, and then
263 * write. It's possible for other code --
264 * specifically, the low-level console -- to have
265 * written in the mean time, which might mean that
266 * there is no longer space. The BERI memory bus will
267 * cause this write to block, wedging the processor
268 * until space is available -- which could be a while
269 * if JTAG is not attached!
271 * The 'easy' fix is to drop the character if WSPACE
272 * has become unset. Not sure what the 'hard' fix is.
274 aju_data_write(sc, ch);
277 * If JTAG is not present, then we will drop this
278 * character instead of perhaps scheduling an
279 * interrupt to let us know when there is buffer
280 * space. Otherwise we might get a write interrupt
281 * later even though we aren't interested in sending
282 * anymore. Loop to drain TTY-layer buffer.
284 if (*sc->ajus_jtag_presentp == 0) {
285 if (ttydisc_getc(tp, &ch, sizeof(ch)) !=
287 panic("%s: ttydisc_getc 2", __func__);
291 if (sc->ajus_irq_res != NULL)
292 aju_intr_writable_enable(sc);
298 aju_intr_writable_disable(sc);
302 aju_outwakeup(struct tty *tp)
304 struct altera_jtag_uart_softc *sc = tty_softc(tp);
306 tty_lock_assert(tp, MA_OWNED);
309 aju_handle_output(sc, tp);
314 aju_io_callout(void *arg)
316 struct altera_jtag_uart_softc *sc = arg;
317 struct tty *tp = sc->ajus_ttyp;
323 * It would be convenient if we could share code with aju_intr() here
324 * by testing the control register for ALTERA_JTAG_UART_CONTROL_RI and
325 * ALTERA_JTAG_UART_CONTROL_WI. Unfortunately, it's not clear that
326 * this is supported, so do all the work to poll for both input and
329 aju_handle_input(sc, tp);
330 aju_handle_output(sc, tp);
333 * Reschedule next poll attempt. There's some argument that we should
334 * do adaptive polling based on the expectation of I/O: is something
335 * pending in the output buffer, or have we recently had input, but we
338 callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
345 aju_ac_callout(void *arg)
347 struct altera_jtag_uart_softc *sc = arg;
348 struct tty *tp = sc->ajus_ttyp;
353 v = aju_control_read(sc);
354 if (v & ALTERA_JTAG_UART_CONTROL_AC) {
355 v &= ~ALTERA_JTAG_UART_CONTROL_AC;
356 aju_control_write(sc, v);
357 if (*sc->ajus_jtag_presentp == 0) {
358 *sc->ajus_jtag_missedp = 0;
359 *sc->ajus_jtag_presentp = 1;
360 aju_handle_output(sc, tp);
362 } else if (*sc->ajus_jtag_presentp != 0) {
363 (*sc->ajus_jtag_missedp)++;
364 if (*sc->ajus_jtag_missedp >= AJU_JTAG_MAXMISS) {
365 *sc->ajus_jtag_presentp = 0;
366 aju_handle_output(sc, tp);
369 callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
378 struct altera_jtag_uart_softc *sc = arg;
379 struct tty *tp = sc->ajus_ttyp;
384 v = aju_control_read(sc);
385 if (v & ALTERA_JTAG_UART_CONTROL_RI)
386 aju_handle_input(sc, tp);
387 if (v & ALTERA_JTAG_UART_CONTROL_WI)
388 aju_handle_output(sc, tp);
394 altera_jtag_uart_attach(struct altera_jtag_uart_softc *sc)
402 * XXXRW: Currently, we detect the console solely based on it using a
403 * reserved address, and borrow console-level locks and buffer if so.
404 * Is there a better way?
406 if (rman_get_start(sc->ajus_mem_res) == BERI_UART_BASE) {
407 sc->ajus_lockp = &aju_cons_lock;
408 sc->ajus_buffer_validp = &aju_cons_buffer_valid;
409 sc->ajus_buffer_datap = &aju_cons_buffer_data;
410 sc->ajus_jtag_presentp = &aju_cons_jtag_present;
411 sc->ajus_jtag_missedp = &aju_cons_jtag_missed;
412 sc->ajus_flags |= ALTERA_JTAG_UART_FLAG_CONSOLE;
414 sc->ajus_lockp = &sc->ajus_lock;
415 sc->ajus_buffer_validp = &sc->ajus_buffer_valid;
416 sc->ajus_buffer_datap = &sc->ajus_buffer_data;
417 sc->ajus_jtag_presentp = &sc->ajus_jtag_present;
418 sc->ajus_jtag_missedp = &sc->ajus_jtag_missed;
422 * Disable interrupts regardless of whether or not we plan to use
423 * them. We will register an interrupt handler now if they will be
424 * used, but not re-enable intil later once the remainder of the tty
425 * layer is properly initialised, as we're not ready for input yet.
428 aju_intr_disable(sc);
430 if (sc->ajus_irq_res != NULL) {
431 error = bus_setup_intr(sc->ajus_dev, sc->ajus_irq_res,
432 INTR_ENTROPY | INTR_TYPE_TTY | INTR_MPSAFE, NULL,
433 aju_intr, sc, &sc->ajus_irq_cookie);
435 device_printf(sc->ajus_dev,
436 "could not activate interrupt\n");
437 AJU_LOCK_DESTROY(sc);
441 tp = sc->ajus_ttyp = tty_alloc(&aju_ttydevsw, sc);
442 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE) {
444 tty_init_console(tp, 0);
446 tty_makedev(tp, NULL, "%s%d", AJU_TTYNAME, sc->ajus_unit);
449 * If we will be using interrupts, enable them now; otherwise, start
450 * polling. From this point onwards, input can arrive.
452 if (sc->ajus_irq_res != NULL) {
454 aju_intr_readable_enable(sc);
457 callout_init(&sc->ajus_io_callout, CALLOUT_MPSAFE);
458 callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL,
461 callout_init(&sc->ajus_ac_callout, CALLOUT_MPSAFE);
462 callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL,
468 altera_jtag_uart_detach(struct altera_jtag_uart_softc *sc)
470 struct tty *tp = sc->ajus_ttyp;
473 * If we're using interrupts, disable and release the interrupt
474 * handler now. Otherwise drain the polling timeout.
476 if (sc->ajus_irq_res != NULL) {
478 aju_intr_disable(sc);
480 bus_teardown_intr(sc->ajus_dev, sc->ajus_irq_res,
481 sc->ajus_irq_cookie);
483 callout_drain(&sc->ajus_io_callout);
484 callout_drain(&sc->ajus_ac_callout);
485 if (sc->ajus_flags & ALTERA_JTAG_UART_FLAG_CONSOLE)
489 AJU_LOCK_DESTROY(sc);