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 #include <sys/rman.h> 51 52 #include <dev/ofw/openfirm.h> 53 #include <ddb/ddb.h> 54 55 #include <vm/vm.h> 56 #include <vm/pmap.h> 57 58 #include <dev/fdt/fdt_common.h> 59 #include <dev/ofw/openfirm.h> 60 #include <dev/ofw/ofw_bus.h> 61 #include <dev/ofw/ofw_bus_subr.h> 62 63 #include <machine/bus.h> 64 #include <machine/cpu.h> 65 #include <machine/intr.h> 66 #include <machine/asm.h> 67 #include <machine/trap.h> 68 #include <machine/vmparam.h> 69 #include <machine/sbi.h> 70 71 static struct resource_spec rcons_spec[] = { 72 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE}, 73 { -1, 0 } 74 }; 75 76 /* bus softc */ 77 struct rcons_softc { 78 struct resource *res[1]; 79 void *ihl[1]; 80 device_t dev; 81 }; 82 83 /* CN Console interface */ 84 85 static tsw_outwakeup_t riscvtty_outwakeup; 86 87 static struct ttydevsw riscv_ttydevsw = { 88 .tsw_flags = TF_NOPREFIX, 89 .tsw_outwakeup = riscvtty_outwakeup, 90 }; 91 92 static int polltime; 93 static struct callout riscv_callout; 94 static struct tty *tp = NULL; 95 96 #if defined(KDB) 97 static int alt_break_state; 98 #endif 99 100 static void riscv_timeout(void *); 101 102 static cn_probe_t riscv_cnprobe; 103 static cn_init_t riscv_cninit; 104 static cn_term_t riscv_cnterm; 105 static cn_getc_t riscv_cngetc; 106 static cn_putc_t riscv_cnputc; 107 static cn_grab_t riscv_cngrab; 108 static cn_ungrab_t riscv_cnungrab; 109 110 CONSOLE_DRIVER(riscv); 111 112 #define MAX_BURST_LEN 1 113 #define QUEUE_SIZE 256 114 115 struct queue_entry { 116 uint64_t data; 117 uint64_t used; 118 struct queue_entry *next; 119 }; 120 121 struct queue_entry cnqueue[QUEUE_SIZE]; 122 struct queue_entry *entry_last; 123 struct queue_entry *entry_served; 124 125 static void 126 riscv_putc(int c) 127 { 128 129 sbi_console_putchar(c); 130 } 131 132 #ifdef EARLY_PRINTF 133 early_putc_t *early_putc = riscv_putc; 134 #endif 135 136 static void 137 cn_drvinit(void *unused) 138 { 139 140 if (riscv_consdev.cn_pri != CN_DEAD && 141 riscv_consdev.cn_name[0] != '\0') { 142 tp = tty_alloc(&riscv_ttydevsw, NULL); 143 tty_init_console(tp, 0); 144 tty_makedev(tp, NULL, "%s", "rcons"); 145 146 polltime = 1; 147 148 callout_init(&riscv_callout, 1); 149 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 150 } 151 } 152 153 SYSINIT(cndev, SI_SUB_CONFIGURE, SI_ORDER_MIDDLE, cn_drvinit, NULL); 154 155 static void 156 riscvtty_outwakeup(struct tty *tp) 157 { 158 u_char buf[MAX_BURST_LEN]; 159 int len; 160 int i; 161 162 for (;;) { 163 len = ttydisc_getc(tp, buf, sizeof(buf)); 164 if (len == 0) 165 break; 166 167 KASSERT(len == 1, ("tty error")); 168 169 for (i = 0; i < len; i++) 170 riscv_putc(buf[i]); 171 } 172 } 173 174 static void 175 riscv_timeout(void *v) 176 { 177 int c; 178 179 tty_lock(tp); 180 while ((c = riscv_cngetc(NULL)) != -1) 181 ttydisc_rint(tp, c, 0); 182 ttydisc_rint_done(tp); 183 tty_unlock(tp); 184 185 callout_reset(&riscv_callout, polltime, riscv_timeout, NULL); 186 } 187 188 static void 189 riscv_cnprobe(struct consdev *cp) 190 { 191 192 cp->cn_pri = CN_NORMAL; 193 } 194 195 static void 196 riscv_cninit(struct consdev *cp) 197 { 198 int i; 199 200 strcpy(cp->cn_name, "rcons"); 201 202 for (i = 0; i < QUEUE_SIZE; i++) { 203 if (i == (QUEUE_SIZE - 1)) 204 cnqueue[i].next = &cnqueue[0]; 205 else 206 cnqueue[i].next = &cnqueue[i+1]; 207 cnqueue[i].data = 0; 208 cnqueue[i].used = 0; 209 } 210 211 entry_last = &cnqueue[0]; 212 entry_served = &cnqueue[0]; 213 } 214 215 static void 216 riscv_cnterm(struct consdev *cp) 217 { 218 219 } 220 221 static void 222 riscv_cngrab(struct consdev *cp) 223 { 224 225 } 226 227 static void 228 riscv_cnungrab(struct consdev *cp) 229 { 230 231 } 232 233 static int 234 riscv_cngetc(struct consdev *cp) 235 { 236 uint8_t data; 237 int ch; 238 239 #if defined(KDB) 240 /* 241 * RISCVTODO: BBL polls for console data on timer interrupt, 242 * but interrupts are turned off in KDB. 243 * So we currently do not have console in KDB. 244 */ 245 if (kdb_active) { 246 ch = sbi_console_getchar(); 247 while (ch) { 248 entry_last->data = ch; 249 entry_last->used = 1; 250 entry_last = entry_last->next; 251 252 ch = sbi_console_getchar(); 253 } 254 } 255 #endif 256 257 if (entry_served->used == 1) { 258 data = entry_served->data; 259 entry_served->used = 0; 260 entry_served = entry_served->next; 261 ch = (data & 0xff); 262 if (ch > 0 && ch < 0xff) { 263 #if defined(KDB) 264 kdb_alt_break(ch, &alt_break_state); 265 #endif 266 return (ch); 267 } 268 } 269 270 return (-1); 271 } 272 273 static void 274 riscv_cnputc(struct consdev *cp, int c) 275 { 276 277 riscv_putc(c); 278 } 279 280 /* Bus interface */ 281 282 static int 283 rcons_intr(void *arg) 284 { 285 int c; 286 287 c = sbi_console_getchar(); 288 if (c > 0 && c < 0xff) { 289 entry_last->data = c; 290 entry_last->used = 1; 291 entry_last = entry_last->next; 292 } 293 294 csr_clear(sip, SIP_SSIP); 295 296 return (FILTER_HANDLED); 297 } 298 299 static int 300 rcons_probe(device_t dev) 301 { 302 303 if (!ofw_bus_status_okay(dev)) 304 return (ENXIO); 305 306 if (!ofw_bus_is_compatible(dev, "riscv,console")) 307 return (ENXIO); 308 309 device_set_desc(dev, "RISC-V console"); 310 return (BUS_PROBE_DEFAULT); 311 } 312 313 static int 314 rcons_attach(device_t dev) 315 { 316 struct rcons_softc *sc; 317 int error; 318 319 sc = device_get_softc(dev); 320 sc->dev = dev; 321 322 if (bus_alloc_resources(dev, rcons_spec, sc->res)) { 323 device_printf(dev, "could not allocate resources\n"); 324 return (ENXIO); 325 } 326 327 /* Setup IRQs handler */ 328 error = bus_setup_intr(dev, sc->res[0], INTR_TYPE_CLK, 329 rcons_intr, NULL, sc, &sc->ihl[0]); 330 if (error) { 331 device_printf(dev, "Unable to alloc int resource.\n"); 332 return (ENXIO); 333 } 334 335 csr_set(sie, SIE_SSIE); 336 337 bus_generic_attach(sc->dev); 338 339 sbi_console_getchar(); 340 341 return (0); 342 } 343 344 static device_method_t rcons_methods[] = { 345 DEVMETHOD(device_probe, rcons_probe), 346 DEVMETHOD(device_attach, rcons_attach), 347 348 DEVMETHOD_END 349 }; 350 351 static driver_t rcons_driver = { 352 "rcons", 353 rcons_methods, 354 sizeof(struct rcons_softc) 355 }; 356 357 static devclass_t rcons_devclass; 358 359 DRIVER_MODULE(rcons, simplebus, rcons_driver, rcons_devclass, 0, 0); 360