xref: /freebsd-11-stable/sys/riscv/htif/htif_console.c (revision 7d536dc855c85c15bf45f033d108a61b1f3cecc3)
1 /*-
2  * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * Portions of this software were developed by SRI International and the
6  * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7  * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Portions of this software were developed by the University of Cambridge
10  * Computer Laboratory as part of the CTSRD Project, with support from the
11  * UK Higher Education Innovation Fund (HEIF).
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/kdb.h>
40 #include <sys/kernel.h>
41 #include <sys/priv.h>
42 #include <sys/systm.h>
43 #include <sys/types.h>
44 #include <sys/conf.h>
45 #include <sys/cons.h>
46 #include <sys/consio.h>
47 #include <sys/tty.h>
48 #include <sys/bus.h>
49 #include <sys/module.h>
50 
51 #include <machine/bus.h>
52 #include <machine/trap.h>
53 
54 #include "htif.h"
55 
56 #include <dev/ofw/openfirm.h>
57 
58 #include <ddb/ddb.h>
59 
60 extern uint64_t console_intr;
61 
62 static tsw_outwakeup_t riscvtty_outwakeup;
63 
64 static struct ttydevsw riscv_ttydevsw = {
65 	.tsw_flags	= TF_NOPREFIX,
66 	.tsw_outwakeup	= riscvtty_outwakeup,
67 };
68 
69 static int			polltime;
70 static struct callout		riscv_callout;
71 static struct tty 		*tp = NULL;
72 
73 #if defined(KDB)
74 static int			alt_break_state;
75 #endif
76 
77 static void	riscv_timeout(void *);
78 
79 static cn_probe_t	riscv_cnprobe;
80 static cn_init_t	riscv_cninit;
81 static cn_term_t	riscv_cnterm;
82 static cn_getc_t	riscv_cngetc;
83 static cn_putc_t	riscv_cnputc;
84 static cn_grab_t	riscv_cngrab;
85 static cn_ungrab_t	riscv_cnungrab;
86 
87 CONSOLE_DRIVER(riscv);
88 
89 #define	MAX_BURST_LEN		1
90 #define	QUEUE_SIZE		256
91 #define	CONSOLE_DEFAULT_ID	1ul
92 #define	SPIN_IN_MACHINE_MODE	1
93 
94 struct queue_entry {
95 	uint64_t data;
96 	uint64_t used;
97 	struct queue_entry *next;
98 };
99 
100 struct queue_entry cnqueue[QUEUE_SIZE];
101 struct queue_entry *entry_last;
102 struct queue_entry *entry_served;
103 
104 static void
htif_putc(int c)105 htif_putc(int c)
106 {
107 	uint64_t cmd;
108 
109 	cmd = (HTIF_CMD_WRITE << HTIF_CMD_SHIFT);
110 	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
111 	cmd |= c;
112 
113 #ifdef SPIN_IN_MACHINE_MODE
114 	machine_command(ECALL_HTIF_LOWPUTC, cmd);
115 #else
116 	htif_command(cmd);
117 #endif
118 
119 }
120 
121 static uint8_t
htif_getc(void)122 htif_getc(void)
123 {
124 	uint64_t cmd;
125 	uint8_t res;
126 
127 	cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT);
128 	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
129 
130 	res = htif_command(cmd);
131 
132 	return (res);
133 }
134 
135 static void
riscv_putc(int c)136 riscv_putc(int c)
137 {
138 	uint64_t counter;
139 	uint64_t *cc;
140 	uint64_t val;
141 
142 	val = 0;
143 	counter = 0;
144 
145 	cc = (uint64_t*)&console_intr;
146 	*cc = 0;
147 
148 	htif_putc(c);
149 
150 #ifndef SPIN_IN_MACHINE_MODE
151 	/* Wait for an interrupt */
152 	__asm __volatile(
153 		"li	%0, 1\n"	/* counter = 1 */
154 		"slli	%0, %0, 12\n"	/* counter <<= 12 */
155 	"1:"
156 		"addi	%0, %0, -1\n"	/* counter -= 1 */
157 		"beqz	%0, 2f\n"	/* counter == 0 ? finish */
158 		"ld	%1, 0(%2)\n"	/* val = *cc */
159 		"beqz	%1, 1b\n"	/* val == 0 ? repeat */
160 	"2:"
161 		: "=&r"(counter), "=&r"(val) : "r"(cc)
162 	);
163 #endif
164 }
165 
166 #ifdef EARLY_PRINTF
167 early_putc_t *early_putc = riscv_putc;
168 #endif
169 
170 static void
cn_drvinit(void * unused)171 cn_drvinit(void *unused)
172 {
173 
174 	if (riscv_consdev.cn_pri != CN_DEAD &&
175 	    riscv_consdev.cn_name[0] != '\0') {
176 		tp = tty_alloc(&riscv_ttydevsw, NULL);
177 		tty_init_console(tp, 0);
178 		tty_makedev(tp, NULL, "%s", "rcons");
179 
180 		polltime = 1;
181 
182 		callout_init(&riscv_callout, 1);
183 		callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
184 	}
185 }
186 
187 SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
188 
189 static void
riscvtty_outwakeup(struct tty * tp)190 riscvtty_outwakeup(struct tty *tp)
191 {
192 	u_char buf[MAX_BURST_LEN];
193 	int len;
194 	int i;
195 
196 	for (;;) {
197 		len = ttydisc_getc(tp, buf, sizeof(buf));
198 		if (len == 0)
199 			break;
200 
201 		KASSERT(len == 1, ("tty error"));
202 
203 		for (i = 0; i < len; i++)
204 			riscv_putc(buf[i]);
205 	}
206 }
207 
208 static void
riscv_timeout(void * v)209 riscv_timeout(void *v)
210 {
211 	int c;
212 
213 	tty_lock(tp);
214 	while ((c = riscv_cngetc(NULL)) != -1)
215 		ttydisc_rint(tp, c, 0);
216 	ttydisc_rint_done(tp);
217 	tty_unlock(tp);
218 
219 	callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
220 }
221 
222 static void
riscv_cnprobe(struct consdev * cp)223 riscv_cnprobe(struct consdev *cp)
224 {
225 
226 	cp->cn_pri = CN_NORMAL;
227 }
228 
229 static void
riscv_cninit(struct consdev * cp)230 riscv_cninit(struct consdev *cp)
231 {
232 	int i;
233 
234 	strcpy(cp->cn_name, "rcons");
235 
236 	for (i = 0; i < QUEUE_SIZE; i++) {
237 		if (i == (QUEUE_SIZE - 1))
238 			cnqueue[i].next = &cnqueue[0];
239 		else
240 			cnqueue[i].next = &cnqueue[i+1];
241 		cnqueue[i].data = 0;
242 		cnqueue[i].used = 0;
243 	}
244 
245 	entry_last = &cnqueue[0];
246 	entry_served = &cnqueue[0];
247 }
248 
249 static void
riscv_cnterm(struct consdev * cp)250 riscv_cnterm(struct consdev *cp)
251 {
252 
253 }
254 
255 static void
riscv_cngrab(struct consdev * cp)256 riscv_cngrab(struct consdev *cp)
257 {
258 
259 }
260 
261 static void
riscv_cnungrab(struct consdev * cp)262 riscv_cnungrab(struct consdev *cp)
263 {
264 
265 }
266 
267 static int
riscv_cngetc(struct consdev * cp)268 riscv_cngetc(struct consdev *cp)
269 {
270 #if defined(KDB)
271 	uint64_t devcmd;
272 	uint64_t entry;
273 	uint64_t devid;
274 #endif
275 	uint8_t data;
276 	int ch;
277 
278 	htif_getc();
279 
280 #if defined(KDB)
281 	if (kdb_active) {
282 		entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
283 		while (entry) {
284 			devid = HTIF_DEV_ID(entry);
285 			devcmd = HTIF_DEV_CMD(entry);
286 			data = HTIF_DEV_DATA(entry);
287 
288 			if (devid == CONSOLE_DEFAULT_ID && devcmd == 0) {
289 				entry_last->data = data;
290 				entry_last->used = 1;
291 				entry_last = entry_last->next;
292 			} else {
293 				printf("Lost interrupt: devid %d\n",
294 				    devid);
295 			}
296 
297 			entry = machine_command(ECALL_HTIF_GET_ENTRY, 0);
298 		}
299 	}
300 #endif
301 
302 	if (entry_served->used == 1) {
303 		data = entry_served->data;
304 		entry_served->used = 0;
305 		entry_served = entry_served->next;
306 		ch = (data & 0xff);
307 		if (ch > 0 && ch < 0xff) {
308 #if defined(KDB)
309 			kdb_alt_break(ch, &alt_break_state);
310 #endif
311 			return (ch);
312 		}
313 	}
314 
315 	return (-1);
316 }
317 
318 static void
riscv_cnputc(struct consdev * cp,int c)319 riscv_cnputc(struct consdev *cp, int c)
320 {
321 
322 	riscv_putc(c);
323 }
324 
325 /*
326  * Bus interface.
327  */
328 
329 struct htif_console_softc {
330 	device_t	dev;
331 	int		running;
332 	int		intr_chan;
333 	int		cmd_done;
334 	int		curtag;
335 	int		index;
336 };
337 
338 static void
htif_console_intr(void * arg,uint64_t entry)339 htif_console_intr(void *arg, uint64_t entry)
340 {
341 	struct htif_console_softc *sc;
342 	uint8_t devcmd;
343 	uint64_t data;
344 
345 	sc = arg;
346 
347 	devcmd = HTIF_DEV_CMD(entry);
348 	data = HTIF_DEV_DATA(entry);
349 
350 	if (devcmd == 0) {
351 		entry_last->data = data;
352 		entry_last->used = 1;
353 		entry_last = entry_last->next;
354 	}
355 }
356 
357 static int
htif_console_probe(device_t dev)358 htif_console_probe(device_t dev)
359 {
360 
361 	return (0);
362 }
363 
364 static int
htif_console_attach(device_t dev)365 htif_console_attach(device_t dev)
366 {
367 	struct htif_console_softc *sc;
368 
369 	sc = device_get_softc(dev);
370 	sc->dev = dev;
371 
372 	sc->index = htif_get_index(dev);
373 	if (sc->index < 0)
374 		return (EINVAL);
375 
376 	htif_setup_intr(sc->index, htif_console_intr, sc);
377 
378 	return (0);
379 }
380 
381 static device_method_t htif_console_methods[] = {
382 	DEVMETHOD(device_probe,		htif_console_probe),
383 	DEVMETHOD(device_attach,	htif_console_attach),
384 	DEVMETHOD_END
385 };
386 
387 static driver_t htif_console_driver = {
388 	"htif_console",
389 	htif_console_methods,
390 	sizeof(struct htif_console_softc)
391 };
392 
393 static devclass_t htif_console_devclass;
394 
395 DRIVER_MODULE(htif_console, htif, htif_console_driver,
396     htif_console_devclass, 0, 0);
397