1 /* $OpenBSD: sfuart.c,v 1.6 2022/07/12 17:14:12 jca Exp $ */
2 /*
3 * Copyright (c) 2019 Mark Kettenis <kettenis@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/conf.h>
20 #include <sys/fcntl.h>
21 #include <sys/proc.h>
22 #include <sys/systm.h>
23 #include <sys/tty.h>
24
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27
28 #include <dev/cons.h>
29
30 #include <dev/ofw/fdt.h>
31 #include <dev/ofw/openfirm.h>
32 #include <dev/ofw/ofw_clock.h>
33
34 #define UART_TXDATA 0x0000
35 #define UART_TXDATA_FULL (1U << 31)
36 #define UART_RXDATA 0x0004
37 #define UART_RXDATA_EMPTY (1U << 31)
38 #define UART_TXCTRL 0x0008
39 #define UART_TXCTRL_TXEN (1 << 0)
40 #define UART_TXCTRL_NSTOP (1 << 1)
41 #define UART_TXCTRL_TXCNT_SHIFT 16
42 #define UART_TXCTRL_TXCNT_MASK (7 << 16)
43 #define UART_RXCTRL 0x000c
44 #define UART_RXCTRL_RXEN (1 << 0)
45 #define UART_RXCTRL_RXCNT_SHIFT 16
46 #define UART_RXCTRL_RXCNT_MASK (7 << 16)
47 #define UART_IE 0x0010
48 #define UART_IE_TXWM (1 << 0)
49 #define UART_IE_RXWM (1 << 1)
50 #define UART_IP 0x0014
51 #define UART_IP_TXWM (1 << 0)
52 #define UART_IP_RXWM (1 << 1)
53 #define UART_DIV 0x0018
54
55 #define UART_SPACE 28
56 #define UART_FIFO_SIZE 8
57
58 #define HREAD4(sc, reg) \
59 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
60 #define HWRITE4(sc, reg, val) \
61 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
62 #define HSET4(sc, reg, bits) \
63 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
64 #define HCLR4(sc, reg, bits) \
65 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
66
67 cdev_decl(com);
68 cdev_decl(sfuart);
69
70 #define DEVUNIT(x) (minor(x) & 0x7f)
71 #define DEVCUA(x) (minor(x) & 0x80)
72
73 struct cdevsw sfuartdev = cdev_tty_init(2, sfuart);
74
75 struct sfuart_softc {
76 struct device sc_dev;
77 bus_space_tag_t sc_iot;
78 bus_space_handle_t sc_ioh;
79
80 uint32_t sc_frequency;
81
82 struct soft_intrhand *sc_si;
83 void *sc_ih;
84
85 struct tty *sc_tty;
86 int sc_conspeed;
87 int sc_floods;
88 int sc_overflows;
89 int sc_halt;
90 int sc_cua;
91 int *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
92 #define SFUART_IBUFSIZE 128
93 #define SFUART_IHIGHWATER 100
94 int sc_ibufs[2][SFUART_IBUFSIZE];
95 };
96
97 int sfuart_match(struct device *, void *, void *);
98 void sfuart_attach(struct device *, struct device *, void *);
99
100 struct cfdriver sfuart_cd = {
101 NULL, "sfuart", DV_TTY
102 };
103
104 const struct cfattach sfuart_ca = {
105 sizeof(struct sfuart_softc), sfuart_match, sfuart_attach
106 };
107
108 bus_space_tag_t sfuartconsiot;
109 bus_space_handle_t sfuartconsioh;
110
111 struct sfuart_softc *sfuart_sc(dev_t);
112
113 int sfuart_intr(void *);
114 void sfuart_softintr(void *);
115 void sfuart_start(struct tty *);
116
117 int sfuartcnattach(bus_space_tag_t, bus_addr_t);
118 int sfuartcngetc(dev_t);
119 void sfuartcnputc(dev_t, int);
120 void sfuartcnpollc(dev_t, int);
121
122 void
sfuart_init_cons(void)123 sfuart_init_cons(void)
124 {
125 struct fdt_reg reg;
126 void *node;
127
128 if ((node = fdt_find_cons("sifive,uart0")) == NULL)
129 return;
130 if (fdt_get_reg(node, 0, ®))
131 return;
132
133 sfuartcnattach(fdt_cons_bs_tag, reg.addr);
134 }
135
136 int
sfuart_match(struct device * parent,void * match,void * aux)137 sfuart_match(struct device *parent, void *match, void *aux)
138 {
139 struct fdt_attach_args *faa = aux;
140
141 return OF_is_compatible(faa->fa_node, "sifive,uart0");
142 }
143
144 void
sfuart_attach(struct device * parent,struct device * self,void * aux)145 sfuart_attach(struct device *parent, struct device *self, void *aux)
146 {
147 struct sfuart_softc *sc = (struct sfuart_softc *)self;
148 struct fdt_attach_args *faa = aux;
149 int maj;
150
151 if (faa->fa_nreg < 1) {
152 printf(": no registers\n");
153 return;
154 }
155
156 sc->sc_iot = faa->fa_iot;
157 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
158 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
159 printf(": can't map registers\n");
160 return;
161 }
162
163 sc->sc_frequency = clock_get_frequency(faa->fa_node, NULL);
164 if (faa->fa_node == stdout_node) {
165 /* Locate the major number. */
166 for (maj = 0; maj < nchrdev; maj++)
167 if (cdevsw[maj].d_open == sfuartopen)
168 break;
169 cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
170 sc->sc_conspeed = stdout_speed;
171 printf(": console");
172 }
173
174 sc->sc_si = softintr_establish(IPL_TTY, sfuart_softintr, sc);
175 if (sc->sc_si == NULL) {
176 printf(": can't establish soft interrupt\n");
177 return;
178 }
179
180 sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
181 sfuart_intr, sc, sc->sc_dev.dv_xname);
182 if (sc->sc_ih == NULL) {
183 printf(": can't establish hard interrupt\n");
184 return;
185 }
186
187 printf("\n");
188 }
189
190 int
sfuart_intr(void * arg)191 sfuart_intr(void *arg)
192 {
193 struct sfuart_softc *sc = arg;
194 struct tty *tp = sc->sc_tty;
195 int *p;
196 uint32_t val;
197 int c, handled = 0;
198
199 if (tp == NULL)
200 return 0;
201
202 if (!ISSET(HREAD4(sc, UART_TXDATA), UART_TXDATA_FULL) &&
203 ISSET(tp->t_state, TS_BUSY)) {
204 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
205 if (sc->sc_halt > 0)
206 wakeup(&tp->t_outq);
207 (*linesw[tp->t_line].l_start)(tp);
208 handled = 1;
209 }
210
211 p = sc->sc_ibufp;
212 val = HREAD4(sc, UART_RXDATA);
213 while (!ISSET(val, UART_RXDATA_EMPTY)) {
214 c = val & 0xff;
215
216 if (p >= sc->sc_ibufend)
217 sc->sc_floods++;
218 else
219 *p++ = c;
220
221 val = HREAD4(sc, UART_RXDATA);
222 handled = 1;
223 }
224 if (sc->sc_ibufp != p) {
225 sc->sc_ibufp = p;
226 softintr_schedule(sc->sc_si);
227 }
228
229 return handled;
230 }
231
232 void
sfuart_softintr(void * arg)233 sfuart_softintr(void *arg)
234 {
235 struct sfuart_softc *sc = arg;
236 struct tty *tp = sc->sc_tty;
237 int *ibufp, *ibufend;
238 int s;
239
240 if (sc->sc_ibufp == sc->sc_ibuf)
241 return;
242
243 s = spltty();
244
245 ibufp = sc->sc_ibuf;
246 ibufend = sc->sc_ibufp;
247
248 if (ibufp == ibufend) {
249 splx(s);
250 return;
251 }
252
253 sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
254 sc->sc_ibufs[1] : sc->sc_ibufs[0];
255 sc->sc_ibufhigh = sc->sc_ibuf + SFUART_IHIGHWATER;
256 sc->sc_ibufend = sc->sc_ibuf + SFUART_IBUFSIZE;
257
258 if (tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
259 splx(s);
260 return;
261 }
262
263 splx(s);
264
265 while (ibufp < ibufend) {
266 int i = *ibufp++;
267 #ifdef DDB
268 if (tp->t_dev == cn_tab->cn_dev) {
269 int j = db_rint(i);
270
271 if (j == 1) /* Escape received, skip */
272 continue;
273 if (j == 2) /* Second char wasn't 'D' */
274 (*linesw[tp->t_line].l_rint)(27, tp);
275 }
276 #endif
277 (*linesw[tp->t_line].l_rint)(i, tp);
278 }
279 }
280
281 int
sfuart_param(struct tty * tp,struct termios * t)282 sfuart_param(struct tty *tp, struct termios *t)
283 {
284 struct sfuart_softc *sc = sfuart_sc(tp->t_dev);
285 int ospeed = t->c_ospeed;
286 uint32_t div;
287
288 /* Check requested parameters. */
289 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
290 return EINVAL;
291
292 switch (ISSET(t->c_cflag, CSIZE)) {
293 case CS5:
294 case CS6:
295 case CS7:
296 return EINVAL;
297 case CS8:
298 break;
299 }
300
301 if (ospeed != 0) {
302 while (ISSET(tp->t_state, TS_BUSY)) {
303 int error;
304
305 sc->sc_halt++;
306 error = ttysleep(tp, &tp->t_outq,
307 TTOPRI | PCATCH, "sfuprm");
308 sc->sc_halt--;
309 if (error) {
310 sfuart_start(tp);
311 return error;
312 }
313 }
314
315 div = (sc->sc_frequency + ospeed / 2) / ospeed;
316 if (div < 16 || div > 65536)
317 return EINVAL;
318 HWRITE4(sc, UART_DIV, div - 1);
319 }
320
321 tp->t_ispeed = t->c_ispeed;
322 tp->t_ospeed = t->c_ospeed;
323 tp->t_cflag = t->c_cflag;
324
325 /* Just to be sure... */
326 sfuart_start(tp);
327 return 0;
328 }
329
330 void
sfuart_start(struct tty * tp)331 sfuart_start(struct tty *tp)
332 {
333 struct sfuart_softc *sc = sfuart_sc(tp->t_dev);
334 int stat;
335 int s;
336
337 s = spltty();
338 if (ISSET(tp->t_state, TS_BUSY))
339 goto out;
340 if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP) || sc->sc_halt > 0)
341 goto out;
342 ttwakeupwr(tp);
343 if (tp->t_outq.c_cc == 0) {
344 HCLR4(sc, UART_IE, UART_IE_TXWM);
345 goto out;
346 }
347 SET(tp->t_state, TS_BUSY);
348
349 stat = HREAD4(sc, UART_TXDATA);
350 while ((stat & UART_TXDATA_FULL) == 0 && tp->t_outq.c_cc != 0) {
351 HWRITE4(sc, UART_TXDATA, getc(&tp->t_outq));
352 stat = HREAD4(sc, UART_TXDATA);
353 }
354 HSET4(sc, UART_IE, UART_IE_TXWM);
355 out:
356 splx(s);
357 }
358
359 int
sfuartopen(dev_t dev,int flag,int mode,struct proc * p)360 sfuartopen(dev_t dev, int flag, int mode, struct proc *p)
361 {
362 struct sfuart_softc *sc = sfuart_sc(dev);
363 struct tty *tp;
364 int error;
365 int s;
366
367 if (sc == NULL)
368 return ENXIO;
369
370 s = spltty();
371 if (sc->sc_tty == NULL)
372 tp = sc->sc_tty = ttymalloc(0);
373 else
374 tp = sc->sc_tty;
375 splx(s);
376
377 tp->t_oproc = sfuart_start;
378 tp->t_param = sfuart_param;
379 tp->t_dev = dev;
380
381 if (!ISSET(tp->t_state, TS_ISOPEN)) {
382 SET(tp->t_state, TS_WOPEN);
383 ttychars(tp);
384 tp->t_iflag = TTYDEF_IFLAG;
385 tp->t_oflag = TTYDEF_OFLAG;
386 tp->t_cflag = TTYDEF_CFLAG;
387 tp->t_lflag = TTYDEF_LFLAG;
388 tp->t_ispeed = tp->t_ospeed =
389 sc->sc_conspeed ? sc->sc_conspeed : B115200;
390
391 s = spltty();
392
393 sfuart_param(tp, &tp->t_termios);
394 ttsetwater(tp);
395
396 sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
397 sc->sc_ibufhigh = sc->sc_ibuf + SFUART_IHIGHWATER;
398 sc->sc_ibufend = sc->sc_ibuf + SFUART_IBUFSIZE;
399
400 /* Enable transmit. */
401 HWRITE4(sc, UART_TXCTRL, UART_TXCTRL_TXEN |
402 ((UART_FIFO_SIZE / 2) << UART_TXCTRL_TXCNT_SHIFT));
403
404 /* Enable receive. */
405 HWRITE4(sc, UART_RXCTRL, UART_RXCTRL_RXEN |
406 (0 << UART_RXCTRL_RXCNT_SHIFT));
407
408 /* Enable interrupts. */
409 HSET4(sc, UART_IE, UART_IE_RXWM);
410
411 /* No carrier detect support. */
412 SET(tp->t_state, TS_CARR_ON);
413 } else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
414 return EBUSY;
415 else
416 s = spltty();
417
418 if (DEVCUA(dev)) {
419 if (ISSET(tp->t_state, TS_ISOPEN)) {
420 /* Ah, but someone already is dialed in... */
421 splx(s);
422 return EBUSY;
423 }
424 sc->sc_cua = 1; /* We go into CUA mode. */
425 } else {
426 if (ISSET(flag, O_NONBLOCK) && sc->sc_cua) {
427 /* Opening TTY non-blocking... but the CUA is busy. */
428 splx(s);
429 return EBUSY;
430 } else {
431 while (sc->sc_cua) {
432 SET(tp->t_state, TS_WOPEN);
433 error = ttysleep(tp, &tp->t_rawq,
434 TTIPRI | PCATCH, ttopen);
435 /*
436 * If TS_WOPEN has been reset, that means the
437 * cua device has been closed.
438 * We don't want to fail in that case,
439 * so just go around again.
440 */
441 if (error && ISSET(tp->t_state, TS_WOPEN)) {
442 CLR(tp->t_state, TS_WOPEN);
443 splx(s);
444 return error;
445 }
446 }
447 }
448 }
449 splx(s);
450
451 return (*linesw[tp->t_line].l_open)(dev, tp, p);
452 }
453
454 int
sfuartclose(dev_t dev,int flag,int mode,struct proc * p)455 sfuartclose(dev_t dev, int flag, int mode, struct proc *p)
456 {
457 struct sfuart_softc *sc = sfuart_sc(dev);
458 struct tty *tp = sc->sc_tty;
459 int s;
460
461 if (!ISSET(tp->t_state, TS_ISOPEN))
462 return 0;
463
464 (*linesw[tp->t_line].l_close)(tp, flag, p);
465 s = spltty();
466 if (!ISSET(tp->t_state, TS_WOPEN)) {
467 /* Disable interrupts */
468 HCLR4(sc, UART_IE, UART_IE_TXWM | UART_IE_RXWM);
469 }
470 CLR(tp->t_state, TS_BUSY | TS_FLUSH);
471 sc->sc_cua = 0;
472 splx(s);
473 ttyclose(tp);
474
475 return 0;
476 }
477
478 int
sfuartread(dev_t dev,struct uio * uio,int flag)479 sfuartread(dev_t dev, struct uio *uio, int flag)
480 {
481 struct tty *tp = sfuarttty(dev);
482
483 if (tp == NULL)
484 return ENODEV;
485
486 return (*linesw[tp->t_line].l_read)(tp, uio, flag);
487 }
488
489 int
sfuartwrite(dev_t dev,struct uio * uio,int flag)490 sfuartwrite(dev_t dev, struct uio *uio, int flag)
491 {
492 struct tty *tp = sfuarttty(dev);
493
494 if (tp == NULL)
495 return ENODEV;
496
497 return (*linesw[tp->t_line].l_write)(tp, uio, flag);
498 }
499
500 int
sfuartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)501 sfuartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
502 {
503 struct sfuart_softc *sc = sfuart_sc(dev);
504 struct tty *tp;
505 int error;
506
507 if (sc == NULL)
508 return ENODEV;
509
510 tp = sc->sc_tty;
511 if (tp == NULL)
512 return ENXIO;
513
514 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
515 if (error >= 0)
516 return error;
517
518 error = ttioctl(tp, cmd, data, flag, p);
519 if (error >= 0)
520 return error;
521
522 switch(cmd) {
523 case TIOCSBRK:
524 case TIOCCBRK:
525 case TIOCSDTR:
526 case TIOCCDTR:
527 case TIOCMSET:
528 case TIOCMBIS:
529 case TIOCMBIC:
530 case TIOCMGET:
531 case TIOCGFLAGS:
532 break;
533 case TIOCSFLAGS:
534 error = suser(p);
535 if (error != 0)
536 return EPERM;
537 break;
538 default:
539 return ENOTTY;
540 }
541
542 return 0;
543 }
544
545 int
sfuartstop(struct tty * tp,int flag)546 sfuartstop(struct tty *tp, int flag)
547 {
548 return 0;
549 }
550
551 struct tty *
sfuarttty(dev_t dev)552 sfuarttty(dev_t dev)
553 {
554 struct sfuart_softc *sc = sfuart_sc(dev);
555
556 if (sc == NULL)
557 return NULL;
558 return sc->sc_tty;
559 }
560
561 struct sfuart_softc *
sfuart_sc(dev_t dev)562 sfuart_sc(dev_t dev)
563 {
564 int unit = DEVUNIT(dev);
565
566 if (unit >= sfuart_cd.cd_ndevs)
567 return NULL;
568 return (struct sfuart_softc *)sfuart_cd.cd_devs[unit];
569 }
570
571 int
sfuartcnattach(bus_space_tag_t iot,bus_addr_t iobase)572 sfuartcnattach(bus_space_tag_t iot, bus_addr_t iobase)
573 {
574 static struct consdev sfuartcons = {
575 NULL, NULL, sfuartcngetc, sfuartcnputc, sfuartcnpollc, NULL,
576 NODEV, CN_MIDPRI
577 };
578 int maj;
579
580 sfuartconsiot = iot;
581 if (bus_space_map(iot, iobase, UART_SPACE, 0, &sfuartconsioh))
582 return ENOMEM;
583
584 /* Look for major of com(4) to replace. */
585 for (maj = 0; maj < nchrdev; maj++)
586 if (cdevsw[maj].d_open == comopen)
587 break;
588 if (maj == nchrdev)
589 return ENXIO;
590
591 cn_tab = &sfuartcons;
592 cn_tab->cn_dev = makedev(maj, 0);
593 cdevsw[maj] = sfuartdev; /* KLUDGE */
594
595 return 0;
596 }
597
598 int
sfuartcngetc(dev_t dev)599 sfuartcngetc(dev_t dev)
600 {
601 uint32_t val;
602
603 do {
604 val = bus_space_read_4(sfuartconsiot, sfuartconsioh, UART_RXDATA);
605 if (val & UART_RXDATA_EMPTY)
606 CPU_BUSY_CYCLE();
607 } while ((val & UART_RXDATA_EMPTY));
608
609 return (val & 0xff);
610 }
611
612 void
sfuartcnputc(dev_t dev,int c)613 sfuartcnputc(dev_t dev, int c)
614 {
615 while (bus_space_read_4(sfuartconsiot, sfuartconsioh, UART_TXDATA) &
616 UART_TXDATA_FULL)
617 CPU_BUSY_CYCLE();
618 bus_space_write_4(sfuartconsiot, sfuartconsioh, UART_TXDATA, c);
619 }
620
621 void
sfuartcnpollc(dev_t dev,int on)622 sfuartcnpollc(dev_t dev, int on)
623 {
624 }
625