htif_console.c revision 295041
1/*-
2 * Copyright (c) 2015 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: head/sys/riscv/htif/htif_console.c 295041 2016-01-29 15:12:31Z br $");
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
60extern uint64_t console_intr;
61
62static tsw_outwakeup_t riscvtty_outwakeup;
63
64static struct ttydevsw riscv_ttydevsw = {
65	.tsw_flags	= TF_NOPREFIX,
66	.tsw_outwakeup	= riscvtty_outwakeup,
67};
68
69static int			polltime;
70static struct callout		riscv_callout;
71static struct tty 		*tp = NULL;
72
73#if defined(KDB)
74static int			alt_break_state;
75#endif
76
77static void	riscv_timeout(void *);
78
79static cn_probe_t	riscv_cnprobe;
80static cn_init_t	riscv_cninit;
81static cn_term_t	riscv_cnterm;
82static cn_getc_t	riscv_cngetc;
83static cn_putc_t	riscv_cnputc;
84static cn_grab_t	riscv_cngrab;
85static cn_ungrab_t	riscv_cnungrab;
86
87CONSOLE_DRIVER(riscv);
88
89#define	MAX_BURST_LEN		1
90#define	QUEUE_SIZE		256
91#define	CONSOLE_DEFAULT_ID	1ul
92
93struct queue_entry {
94	uint64_t data;
95	uint64_t used;
96	struct queue_entry *next;
97};
98
99struct queue_entry cnqueue[QUEUE_SIZE];
100struct queue_entry *entry_last;
101struct queue_entry *entry_served;
102
103static void
104htif_putc(int c)
105{
106	uint64_t cmd;
107
108	cmd = (HTIF_CMD_WRITE << HTIF_CMD_SHIFT);
109	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
110	cmd |= c;
111
112	htif_command(cmd);
113}
114
115static uint8_t
116htif_getc(void)
117{
118	uint64_t cmd;
119	uint8_t res;
120
121	cmd = (HTIF_CMD_READ << HTIF_CMD_SHIFT);
122	cmd |= (CONSOLE_DEFAULT_ID << HTIF_DEV_ID_SHIFT);
123
124	res = htif_command(cmd);
125
126	return (res);
127}
128
129static void
130riscv_putc(int c)
131{
132	uint64_t counter;
133	uint64_t *cc;
134	uint64_t val;
135
136	val = 0;
137	counter = 0;
138
139	cc = (uint64_t*)&console_intr;
140	*cc = 0;
141
142	htif_putc(c);
143
144	/* Wait for an interrupt */
145	__asm __volatile(
146		"li	%0, 1\n"	/* counter = 1 */
147		"slli	%0, %0, 12\n"	/* counter <<= 12 */
148	"1:"
149		"addi	%0, %0, -1\n"	/* counter -= 1 */
150		"beqz	%0, 2f\n"	/* counter == 0 ? finish */
151		"ld	%1, 0(%2)\n"	/* val = *cc */
152		"beqz	%1, 1b\n"	/* val == 0 ? repeat */
153	"2:"
154		: "=&r"(counter), "=&r"(val) : "r"(cc)
155	);
156}
157
158#ifdef EARLY_PRINTF
159early_putc_t *early_putc = riscv_putc;
160#endif
161
162static void
163cn_drvinit(void *unused)
164{
165
166	if (riscv_consdev.cn_pri != CN_DEAD &&
167	    riscv_consdev.cn_name[0] != '\0') {
168		tp = tty_alloc(&riscv_ttydevsw, NULL);
169		tty_init_console(tp, 0);
170		tty_makedev(tp, NULL, "%s", "rcons");
171
172		polltime = 1;
173
174		callout_init(&riscv_callout, 1);
175		callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
176	}
177}
178
179SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL);
180
181static void
182riscvtty_outwakeup(struct tty *tp)
183{
184	u_char buf[MAX_BURST_LEN];
185	int len;
186	int i;
187
188	for (;;) {
189		len = ttydisc_getc(tp, buf, sizeof(buf));
190		if (len == 0)
191			break;
192
193		KASSERT(len == 1, ("tty error"));
194
195		for (i = 0; i < len; i++)
196			riscv_putc(buf[i]);
197	}
198}
199
200static void
201riscv_timeout(void *v)
202{
203	int c;
204
205	tty_lock(tp);
206	while ((c = riscv_cngetc(NULL)) != -1)
207		ttydisc_rint(tp, c, 0);
208	ttydisc_rint_done(tp);
209	tty_unlock(tp);
210
211	callout_reset(&riscv_callout, polltime, riscv_timeout, NULL);
212}
213
214static void
215riscv_cnprobe(struct consdev *cp)
216{
217
218	cp->cn_pri = CN_NORMAL;
219}
220
221static void
222riscv_cninit(struct consdev *cp)
223{
224	int i;
225
226	strcpy(cp->cn_name, "rcons");
227
228	for (i = 0; i < QUEUE_SIZE; i++) {
229		if (i == (QUEUE_SIZE - 1))
230			cnqueue[i].next = &cnqueue[0];
231		else
232			cnqueue[i].next = &cnqueue[i+1];
233		cnqueue[i].data = 0;
234		cnqueue[i].used = 0;
235	}
236
237	entry_last = &cnqueue[0];
238	entry_served = &cnqueue[0];
239}
240
241static void
242riscv_cnterm(struct consdev *cp)
243{
244
245}
246
247static void
248riscv_cngrab(struct consdev *cp)
249{
250
251}
252
253static void
254riscv_cnungrab(struct consdev *cp)
255{
256
257}
258
259static int
260riscv_cngetc(struct consdev *cp)
261{
262	uint8_t data;
263	int ch;
264
265	ch = htif_getc();
266
267	if (entry_served->used == 1) {
268		data = entry_served->data;
269		entry_served->used = 0;
270		entry_served = entry_served->next;
271		ch = (data & 0xff);
272		if (ch > 0 && ch < 0xff) {
273#if defined(KDB)
274			kdb_alt_break(ch, &alt_break_state);
275#endif
276			return (ch);
277		}
278	}
279
280	return (-1);
281}
282
283static void
284riscv_cnputc(struct consdev *cp, int c)
285{
286
287	riscv_putc(c);
288}
289
290/*
291 * Bus interface.
292 */
293
294struct htif_console_softc {
295	device_t	dev;
296	int		running;
297	int		intr_chan;
298	int		cmd_done;
299	int		curtag;
300	int		index;
301};
302
303static void
304htif_console_intr(void *arg, uint64_t entry)
305{
306	struct htif_console_softc *sc;
307	uint8_t devcmd;
308	uint64_t data;
309
310	sc = arg;
311
312	devcmd = HTIF_DEV_CMD(entry);
313	data = HTIF_DEV_DATA(entry);
314
315	if (devcmd == 0) {
316		entry_last->data = data;
317		entry_last->used = 1;
318		entry_last = entry_last->next;
319	}
320}
321
322static int
323htif_console_probe(device_t dev)
324{
325
326	return (0);
327}
328
329static int
330htif_console_attach(device_t dev)
331{
332	struct htif_console_softc *sc;
333
334	sc = device_get_softc(dev);
335	sc->dev = dev;
336
337	sc->index = htif_get_index(dev);
338	if (sc->index < 0)
339		return (EINVAL);
340
341	htif_setup_intr(sc->index, htif_console_intr, sc);
342
343	return (0);
344}
345
346static device_method_t htif_console_methods[] = {
347	DEVMETHOD(device_probe,		htif_console_probe),
348	DEVMETHOD(device_attach,	htif_console_attach),
349	DEVMETHOD_END
350};
351
352static driver_t htif_console_driver = {
353	"htif_console",
354	htif_console_methods,
355	sizeof(struct htif_console_softc)
356};
357
358static devclass_t htif_console_devclass;
359
360DRIVER_MODULE(htif_console, htif, htif_console_driver,
361    htif_console_devclass, 0, 0);
362