1697a77c1SRobert Watson /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4697a77c1SRobert Watson  * Copyright (c) 2011-2012 Robert N. M. Watson
5697a77c1SRobert Watson  * All rights reserved.
6697a77c1SRobert Watson  *
7697a77c1SRobert Watson  * This software was developed by SRI International and the University of
8697a77c1SRobert Watson  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9697a77c1SRobert Watson  * ("CTSRD"), as part of the DARPA CRASH research programme.
10697a77c1SRobert Watson  *
11697a77c1SRobert Watson  * Redistribution and use in source and binary forms, with or without
12697a77c1SRobert Watson  * modification, are permitted provided that the following conditions
13697a77c1SRobert Watson  * are met:
14697a77c1SRobert Watson  * 1. Redistributions of source code must retain the above copyright
15697a77c1SRobert Watson  *    notice, this list of conditions and the following disclaimer.
16697a77c1SRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
17697a77c1SRobert Watson  *    notice, this list of conditions and the following disclaimer in the
18697a77c1SRobert Watson  *    documentation and/or other materials provided with the distribution.
19697a77c1SRobert Watson  *
20697a77c1SRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21697a77c1SRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22697a77c1SRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23697a77c1SRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24697a77c1SRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25697a77c1SRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26697a77c1SRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27697a77c1SRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28697a77c1SRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29697a77c1SRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30697a77c1SRobert Watson  * SUCH DAMAGE.
31697a77c1SRobert Watson  */
32697a77c1SRobert Watson 
33697a77c1SRobert Watson #include <sys/param.h>
346a347d02SRobert Watson #include <sys/bus.h>
35697a77c1SRobert Watson #include <sys/cons.h>
36697a77c1SRobert Watson #include <sys/endian.h>
37697a77c1SRobert Watson #include <sys/kdb.h>
38697a77c1SRobert Watson #include <sys/kernel.h>
39697a77c1SRobert Watson #include <sys/lock.h>
40697a77c1SRobert Watson #include <sys/mutex.h>
41697a77c1SRobert Watson #include <sys/reboot.h>
4295fadd99SRobert Watson #include <sys/sysctl.h>
43697a77c1SRobert Watson #include <sys/systm.h>
44697a77c1SRobert Watson #include <sys/tty.h>
45697a77c1SRobert Watson 
46697a77c1SRobert Watson #include <ddb/ddb.h>
47697a77c1SRobert Watson 
48697a77c1SRobert Watson #include <dev/altera/jtag_uart/altera_jtag_uart.h>
49697a77c1SRobert Watson 
507029da5cSPawel Biernacki static SYSCTL_NODE(_hw, OID_AUTO, altera_jtag_uart,
517029da5cSPawel Biernacki     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
5295fadd99SRobert Watson     "Altera JTAG UART configuration knobs");
5395fadd99SRobert Watson 
54697a77c1SRobert Watson /*
55697a77c1SRobert Watson  * One-byte buffer as we can't check whether the UART is readable without
56697a77c1SRobert Watson  * actually reading from it, synchronised by a spinlock; this lock also
57697a77c1SRobert Watson  * synchronises access to the I/O ports for non-atomic sequences.  These
58697a77c1SRobert Watson  * symbols are public so that the TTY layer can use them when working on an
59697a77c1SRobert Watson  * instance of the UART that is also a low-level console.
60697a77c1SRobert Watson  */
61697a77c1SRobert Watson char		aju_cons_buffer_data;
62697a77c1SRobert Watson int		aju_cons_buffer_valid;
63697a77c1SRobert Watson int		aju_cons_jtag_present;
64697a77c1SRobert Watson u_int		aju_cons_jtag_missed;
65697a77c1SRobert Watson struct mtx	aju_cons_lock;
66697a77c1SRobert Watson 
67697a77c1SRobert Watson /*
68697a77c1SRobert Watson  * Low-level console driver functions.
69697a77c1SRobert Watson  */
70697a77c1SRobert Watson static cn_probe_t	aju_cnprobe;
71697a77c1SRobert Watson static cn_init_t	aju_cninit;
72697a77c1SRobert Watson static cn_term_t	aju_cnterm;
73697a77c1SRobert Watson static cn_getc_t	aju_cngetc;
74697a77c1SRobert Watson static cn_putc_t	aju_cnputc;
75697a77c1SRobert Watson static cn_grab_t	aju_cngrab;
76697a77c1SRobert Watson static cn_ungrab_t	aju_cnungrab;
77697a77c1SRobert Watson 
78697a77c1SRobert Watson /*
79697a77c1SRobert Watson  * JTAG sets the ALTERA_JTAG_UART_CONTROL_AC bit whenever it accesses the
80697a77c1SRobert Watson  * FIFO.  This allows us to (sort of) tell when JTAG is present, so that we
81697a77c1SRobert Watson  * can adopt lossy, rather than blocking, behaviour when JTAG isn't there.
82697a77c1SRobert Watson  * When it is present, we do full flow control.  This delay is how long we
83697a77c1SRobert Watson  * wait to see if JTAG has really disappeared when finding a full buffer and
84697a77c1SRobert Watson  * no AC bit set.
85697a77c1SRobert Watson  */
86697a77c1SRobert Watson #define	ALTERA_JTAG_UART_AC_POLL_DELAY	10000
8795fadd99SRobert Watson static u_int	altera_jtag_uart_ac_poll_delay =
8895fadd99SRobert Watson 		    ALTERA_JTAG_UART_AC_POLL_DELAY;
8995fadd99SRobert Watson SYSCTL_UINT(_hw_altera_jtag_uart, OID_AUTO, ac_poll_delay,
9095fadd99SRobert Watson     CTLFLAG_RW, &altera_jtag_uart_ac_poll_delay, 0,
9195fadd99SRobert Watson     "Maximum delay waiting for JTAG present flag when buffer is full");
92697a77c1SRobert Watson 
93697a77c1SRobert Watson /*
94697a77c1SRobert Watson  * I/O routines lifted from Deimos.  This is not only MIPS-specific, but also
9596240c89SEitan Adler  * BERI-specific, as we're hard coding the address at which we expect to
96697a77c1SRobert Watson  * find the Altera JTAG UART and using it unconditionally.  We use these
97697a77c1SRobert Watson  * low-level routines so that we can perform console I/O long before newbus
98697a77c1SRobert Watson  * has initialised and devices have attached.  The TTY layer of the driver
99697a77c1SRobert Watson  * knows about this, and uses the console-layer spinlock instead of the
100697a77c1SRobert Watson  * TTY-layer lock to avoid confusion between layers for the console UART.
101697a77c1SRobert Watson  *
102697a77c1SRobert Watson  * XXXRW: The only place this inter-layer behaviour breaks down is if the
103697a77c1SRobert Watson  * low-level console is used for polled read while the TTY driver is also
104697a77c1SRobert Watson  * looking for input.  Probably we should also share buffers between layers.
105697a77c1SRobert Watson  */
106697a77c1SRobert Watson #define	MIPS_XKPHYS_UNCACHED_BASE	0x9000000000000000
107697a77c1SRobert Watson 
108697a77c1SRobert Watson typedef	uint64_t	paddr_t;
109697a77c1SRobert Watson typedef	uint64_t	vaddr_t;
110697a77c1SRobert Watson 
111697a77c1SRobert Watson static inline vaddr_t
mips_phys_to_uncached(paddr_t phys)112697a77c1SRobert Watson mips_phys_to_uncached(paddr_t phys)
113697a77c1SRobert Watson {
114697a77c1SRobert Watson 
115697a77c1SRobert Watson 	return (phys | MIPS_XKPHYS_UNCACHED_BASE);
116697a77c1SRobert Watson }
117697a77c1SRobert Watson 
118697a77c1SRobert Watson static inline uint32_t
mips_ioread_uint32(vaddr_t vaddr)119697a77c1SRobert Watson mips_ioread_uint32(vaddr_t vaddr)
120697a77c1SRobert Watson {
121697a77c1SRobert Watson 	uint32_t v;
122697a77c1SRobert Watson 
123697a77c1SRobert Watson 	__asm__ __volatile__ ("lw %0, 0(%1)" : "=r" (v) : "r" (vaddr));
124697a77c1SRobert Watson 	return (v);
125697a77c1SRobert Watson }
126697a77c1SRobert Watson 
127697a77c1SRobert Watson static inline void
mips_iowrite_uint32(vaddr_t vaddr,uint32_t v)128697a77c1SRobert Watson mips_iowrite_uint32(vaddr_t vaddr, uint32_t v)
129697a77c1SRobert Watson {
130697a77c1SRobert Watson 
131697a77c1SRobert Watson 	__asm__ __volatile__ ("sw %0, 0(%1)" : : "r" (v), "r" (vaddr));
132697a77c1SRobert Watson }
133697a77c1SRobert Watson 
134697a77c1SRobert Watson /*
135697a77c1SRobert Watson  * Little-endian versions of 32-bit I/O routines.
136697a77c1SRobert Watson  */
137697a77c1SRobert Watson static inline uint32_t
mips_ioread_uint32le(vaddr_t vaddr)138697a77c1SRobert Watson mips_ioread_uint32le(vaddr_t vaddr)
139697a77c1SRobert Watson {
140697a77c1SRobert Watson 
141697a77c1SRobert Watson 	return (le32toh(mips_ioread_uint32(vaddr)));
142697a77c1SRobert Watson }
143697a77c1SRobert Watson 
144697a77c1SRobert Watson static inline void
mips_iowrite_uint32le(vaddr_t vaddr,uint32_t v)145697a77c1SRobert Watson mips_iowrite_uint32le(vaddr_t vaddr, uint32_t v)
146697a77c1SRobert Watson {
147697a77c1SRobert Watson 
148697a77c1SRobert Watson 	mips_iowrite_uint32(vaddr, htole32(v));
149697a77c1SRobert Watson }
150697a77c1SRobert Watson 
151697a77c1SRobert Watson /*
152697a77c1SRobert Watson  * Low-level read and write register routines; the Altera UART is little
153697a77c1SRobert Watson  * endian, so we byte swap 32-bit reads and writes.
154697a77c1SRobert Watson  */
155697a77c1SRobert Watson static inline uint32_t
aju_cons_data_read(void)156697a77c1SRobert Watson aju_cons_data_read(void)
157697a77c1SRobert Watson {
158697a77c1SRobert Watson 
159697a77c1SRobert Watson 	return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
160697a77c1SRobert Watson 	    ALTERA_JTAG_UART_DATA_OFF)));
161697a77c1SRobert Watson }
162697a77c1SRobert Watson 
163697a77c1SRobert Watson static inline void
aju_cons_data_write(uint32_t v)164697a77c1SRobert Watson aju_cons_data_write(uint32_t v)
165697a77c1SRobert Watson {
166697a77c1SRobert Watson 
167697a77c1SRobert Watson 	mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
168697a77c1SRobert Watson 	    ALTERA_JTAG_UART_DATA_OFF), v);
169697a77c1SRobert Watson }
170697a77c1SRobert Watson 
171697a77c1SRobert Watson static inline uint32_t
aju_cons_control_read(void)172697a77c1SRobert Watson aju_cons_control_read(void)
173697a77c1SRobert Watson {
174697a77c1SRobert Watson 
175697a77c1SRobert Watson 	return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
176697a77c1SRobert Watson 	    ALTERA_JTAG_UART_CONTROL_OFF)));
177697a77c1SRobert Watson }
178697a77c1SRobert Watson 
179697a77c1SRobert Watson static inline void
aju_cons_control_write(uint32_t v)180697a77c1SRobert Watson aju_cons_control_write(uint32_t v)
181697a77c1SRobert Watson {
182697a77c1SRobert Watson 
183697a77c1SRobert Watson 	mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
184697a77c1SRobert Watson 	    ALTERA_JTAG_UART_CONTROL_OFF), v);
185697a77c1SRobert Watson }
186697a77c1SRobert Watson 
187697a77c1SRobert Watson /*
188697a77c1SRobert Watson  * Slightly higher-level routines aware of buffering and flow control.
189697a77c1SRobert Watson  */
190697a77c1SRobert Watson static int
aju_cons_readable(void)191697a77c1SRobert Watson aju_cons_readable(void)
192697a77c1SRobert Watson {
193697a77c1SRobert Watson 	uint32_t v;
194697a77c1SRobert Watson 
195697a77c1SRobert Watson 	AJU_CONSOLE_LOCK_ASSERT();
196697a77c1SRobert Watson 
197697a77c1SRobert Watson 	if (aju_cons_buffer_valid)
198697a77c1SRobert Watson 		return (1);
199697a77c1SRobert Watson 	v = aju_cons_data_read();
200697a77c1SRobert Watson 	if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
201697a77c1SRobert Watson 		aju_cons_buffer_valid = 1;
202697a77c1SRobert Watson 		aju_cons_buffer_data = (v & ALTERA_JTAG_UART_DATA_DATA);
203697a77c1SRobert Watson 		return (1);
204697a77c1SRobert Watson 	}
205697a77c1SRobert Watson 	return (0);
206697a77c1SRobert Watson }
207697a77c1SRobert Watson 
208697a77c1SRobert Watson static void
aju_cons_write(char ch)209697a77c1SRobert Watson aju_cons_write(char ch)
210697a77c1SRobert Watson {
211697a77c1SRobert Watson 	uint32_t v;
212697a77c1SRobert Watson 
213697a77c1SRobert Watson 	AJU_CONSOLE_LOCK_ASSERT();
214697a77c1SRobert Watson 
215697a77c1SRobert Watson 	/*
216697a77c1SRobert Watson 	 * The flow control logic here is somewhat subtle: we want to wait for
217697a77c1SRobert Watson 	 * write buffer space only while JTAG is present.  However, we can't
218697a77c1SRobert Watson 	 * directly ask if JTAG is present -- just whether it's been seen
219697a77c1SRobert Watson 	 * since we last cleared the ALTERA_JTAG_UART_CONTROL_AC bit.  As
220697a77c1SRobert Watson 	 * such, implement a polling loop in which we both wait for space and
221697a77c1SRobert Watson 	 * try to decide whether JTAG has disappeared on us.  We will have to
222697a77c1SRobert Watson 	 * wait one complete polling delay to detect that JTAG has gone away,
223697a77c1SRobert Watson 	 * but otherwise shouldn't wait any further once it has gone.  And we
224697a77c1SRobert Watson 	 * had to wait for buffer space anyway, if it was there.
225697a77c1SRobert Watson 	 *
226697a77c1SRobert Watson 	 * If JTAG is spotted, reset the TTY-layer miss counter so console-
227697a77c1SRobert Watson 	 * layer clearing of the bit doesn't trigger a TTY-layer
228697a77c1SRobert Watson 	 * disconnection.
229697a77c1SRobert Watson 	 *
230a1f76946SBrooks Davis 	 * XXXRW: Notice the inherent race with hardware: in clearing the
23195fadd99SRobert Watson 	 * bit, we may race with hardware setting the same bit.  This can
23295fadd99SRobert Watson 	 * cause real-world reliability problems due to lost output on the
23395fadd99SRobert Watson 	 * console.
234697a77c1SRobert Watson 	 */
235697a77c1SRobert Watson 	v = aju_cons_control_read();
236697a77c1SRobert Watson 	if (v & ALTERA_JTAG_UART_CONTROL_AC) {
237697a77c1SRobert Watson 		aju_cons_jtag_present = 1;
238697a77c1SRobert Watson 		aju_cons_jtag_missed = 0;
239697a77c1SRobert Watson 		v &= ~ALTERA_JTAG_UART_CONTROL_AC;
240697a77c1SRobert Watson 		aju_cons_control_write(v);
241697a77c1SRobert Watson 	}
242697a77c1SRobert Watson 	while ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) {
243697a77c1SRobert Watson 		if (!aju_cons_jtag_present)
244697a77c1SRobert Watson 			return;
24595fadd99SRobert Watson 		DELAY(altera_jtag_uart_ac_poll_delay);
246697a77c1SRobert Watson 		v = aju_cons_control_read();
247697a77c1SRobert Watson 		if (v & ALTERA_JTAG_UART_CONTROL_AC) {
248697a77c1SRobert Watson 			aju_cons_jtag_present = 1;
249697a77c1SRobert Watson 			v &= ~ALTERA_JTAG_UART_CONTROL_AC;
250697a77c1SRobert Watson 			aju_cons_control_write(v);
251697a77c1SRobert Watson 		} else
252697a77c1SRobert Watson 			aju_cons_jtag_present = 0;
253697a77c1SRobert Watson 	}
254697a77c1SRobert Watson 	aju_cons_data_write(ch);
255697a77c1SRobert Watson }
256697a77c1SRobert Watson 
257697a77c1SRobert Watson static char
aju_cons_read(void)258697a77c1SRobert Watson aju_cons_read(void)
259697a77c1SRobert Watson {
260697a77c1SRobert Watson 
261697a77c1SRobert Watson 	AJU_CONSOLE_LOCK_ASSERT();
262697a77c1SRobert Watson 
263697a77c1SRobert Watson 	while (!aju_cons_readable());
264697a77c1SRobert Watson 	aju_cons_buffer_valid = 0;
265697a77c1SRobert Watson 	return (aju_cons_buffer_data);
266697a77c1SRobert Watson }
267697a77c1SRobert Watson 
268697a77c1SRobert Watson /*
269697a77c1SRobert Watson  * Implementation of a FreeBSD low-level, polled console driver.
270697a77c1SRobert Watson  */
271697a77c1SRobert Watson static void
aju_cnprobe(struct consdev * cp)272697a77c1SRobert Watson aju_cnprobe(struct consdev *cp)
273697a77c1SRobert Watson {
274697a77c1SRobert Watson 
275697a77c1SRobert Watson 	sprintf(cp->cn_name, "%s%d", AJU_TTYNAME, 0);
276697a77c1SRobert Watson 	cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
277697a77c1SRobert Watson }
278697a77c1SRobert Watson 
279697a77c1SRobert Watson static void
aju_cninit(struct consdev * cp)280697a77c1SRobert Watson aju_cninit(struct consdev *cp)
281697a77c1SRobert Watson {
282697a77c1SRobert Watson 	uint32_t v;
283697a77c1SRobert Watson 
284697a77c1SRobert Watson 	AJU_CONSOLE_LOCK_INIT();
285697a77c1SRobert Watson 
286697a77c1SRobert Watson 	AJU_CONSOLE_LOCK();
287697a77c1SRobert Watson 	v = aju_cons_control_read();
288697a77c1SRobert Watson 	v &= ~ALTERA_JTAG_UART_CONTROL_AC;
289697a77c1SRobert Watson 	aju_cons_control_write(v);
290697a77c1SRobert Watson 	AJU_CONSOLE_UNLOCK();
291697a77c1SRobert Watson }
292697a77c1SRobert Watson 
293697a77c1SRobert Watson static void
aju_cnterm(struct consdev * cp)294697a77c1SRobert Watson aju_cnterm(struct consdev *cp)
295697a77c1SRobert Watson {
296697a77c1SRobert Watson 
297697a77c1SRobert Watson }
298697a77c1SRobert Watson 
299697a77c1SRobert Watson static int
aju_cngetc(struct consdev * cp)300697a77c1SRobert Watson aju_cngetc(struct consdev *cp)
301697a77c1SRobert Watson {
302697a77c1SRobert Watson 	int ret;
303697a77c1SRobert Watson 
304697a77c1SRobert Watson 	AJU_CONSOLE_LOCK();
305697a77c1SRobert Watson 	ret = aju_cons_read();
306697a77c1SRobert Watson 	AJU_CONSOLE_UNLOCK();
307697a77c1SRobert Watson 	return (ret);
308697a77c1SRobert Watson }
309697a77c1SRobert Watson 
310697a77c1SRobert Watson static void
aju_cnputc(struct consdev * cp,int c)311697a77c1SRobert Watson aju_cnputc(struct consdev *cp, int c)
312697a77c1SRobert Watson {
313697a77c1SRobert Watson 
314697a77c1SRobert Watson 	AJU_CONSOLE_LOCK();
315697a77c1SRobert Watson 	aju_cons_write(c);
316697a77c1SRobert Watson 	AJU_CONSOLE_UNLOCK();
317697a77c1SRobert Watson }
318697a77c1SRobert Watson 
319697a77c1SRobert Watson static void
aju_cngrab(struct consdev * cp)320697a77c1SRobert Watson aju_cngrab(struct consdev *cp)
321697a77c1SRobert Watson {
322697a77c1SRobert Watson 
323697a77c1SRobert Watson }
324697a77c1SRobert Watson 
325697a77c1SRobert Watson static void
aju_cnungrab(struct consdev * cp)326697a77c1SRobert Watson aju_cnungrab(struct consdev *cp)
327697a77c1SRobert Watson {
328697a77c1SRobert Watson 
329697a77c1SRobert Watson }
330697a77c1SRobert Watson 
331697a77c1SRobert Watson CONSOLE_DRIVER(aju);
332