xref: /openbsd/sys/dev/fdt/cduart.c (revision 282e735e)
1 /*	$OpenBSD: cduart.c,v 1.1 2021/04/24 07:49:11 visa Exp $	*/
2 
3 /*
4  * Copyright (c) 2021 Visa Hankala
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Driver for Cadence UART.
21  */
22 
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/conf.h>
26 #include <sys/device.h>
27 #include <sys/fcntl.h>
28 #include <sys/tty.h>
29 #include <sys/syslog.h>
30 
31 #include <machine/bus.h>
32 #include <machine/fdt.h>
33 
34 #include <dev/cons.h>
35 
36 #include <dev/ofw/fdt.h>
37 #include <dev/ofw/openfirm.h>
38 
39 #define CDUART_CR			0x0000
40 #define  CDUART_CR_STOPBRK			(1 << 8)
41 #define  CDUART_CR_STARTBRK			(1 << 7)
42 #define  CDUART_CR_TORST			(1 << 6)
43 #define  CDUART_CR_TXDIS			(1 << 5)
44 #define  CDUART_CR_TXEN				(1 << 4)
45 #define  CDUART_CR_RXDIS			(1 << 3)
46 #define  CDUART_CR_RXEN				(1 << 2)
47 #define  CDUART_CR_TXRST			(1 << 1)
48 #define  CDUART_CR_RXRST			(1 << 0)
49 #define CDUART_MR			0x0004
50 #define  CDUART_MR_CHMODE_MASK			(0x3 << 8)
51 #define  CDUART_MR_NBSTOP_MASK			(0x3 << 6)
52 #define  CDUART_MR_PAR_MASK			(0x7 << 3)
53 #define  CDUART_MR_PAR_NO			(0x4 << 3)
54 #define  CDUART_MR_PAR_FORCED1			(0x3 << 3)
55 #define  CDUART_MR_PAR_FORCED0			(0x2 << 3)
56 #define  CDUART_MR_PAR_ODD			(0x1 << 3)
57 #define  CDUART_MR_PAR_EVEN			(0x0 << 3)
58 #define  CDUART_MR_CHRL_MASK			(0x3 << 1)
59 #define  CDUART_MR_CHRL_C6			(0x3 << 1)
60 #define  CDUART_MR_CHRL_C7			(0x2 << 1)
61 #define  CDUART_MR_CHRL_C8			(0x0 << 1)
62 #define  CDUART_MR_CLKSEL			(1 << 0)
63 #define CDUART_IER			0x0008
64 #define CDUART_IDR			0x000c
65 #define CDUART_IMR			0x0010
66 #define CDUART_ISR			0x0014
67 #define  CDUART_ISR_TXOVR			(1 << 12)
68 #define  CDUART_ISR_TNFUL			(1 << 11)
69 #define  CDUART_ISR_TTRIG			(1 << 10)
70 #define  CDUART_IXR_DMS				(1 << 9)
71 #define  CDUART_IXR_TOUT			(1 << 8)
72 #define  CDUART_IXR_PARITY			(1 << 7)
73 #define  CDUART_IXR_FRAMING			(1 << 6)
74 #define  CDUART_IXR_RXOVR			(1 << 5)
75 #define  CDUART_IXR_TXFULL			(1 << 4)
76 #define  CDUART_IXR_TXEMPTY			(1 << 3)
77 #define  CDUART_IXR_RXFULL			(1 << 2)
78 #define  CDUART_IXR_RXEMPTY			(1 << 1)
79 #define  CDUART_IXR_RTRIG			(1 << 0)
80 #define CDUART_RXTOUT			0x001c
81 #define CDUART_RXWM			0x0020
82 #define CDUART_SR			0x002c
83 #define  CDUART_SR_TNFUL			(1 << 14)
84 #define  CDUART_SR_TTRIG			(1 << 13)
85 #define  CDUART_SR_FLOWDEL			(1 << 12)
86 #define  CDUART_SR_TACTIVE			(1 << 11)
87 #define  CDUART_SR_RACTIVE			(1 << 10)
88 #define  CDUART_SR_TXFULL			(1 << 4)
89 #define  CDUART_SR_TXEMPTY			(1 << 3)
90 #define  CDUART_SR_RXFULL			(1 << 2)
91 #define  CDUART_SR_RXEMPTY			(1 << 1)
92 #define  CDUART_SR_RXOVR			(1 << 0)
93 #define CDUART_FIFO			0x0030
94 
95 #define CDUART_SPACE_SIZE		0x0048
96 
97 #define CDUART_FIFOSIZE		64
98 #define CDUART_IBUFSIZE		128
99 
100 struct cduart_softc {
101 	struct device		sc_dev;
102 	bus_space_tag_t		sc_iot;
103 	bus_space_handle_t	sc_ioh;
104 	void			*sc_ih;
105 	void			*sc_si;
106 
107 	struct tty		*sc_tty;
108 	uint8_t			sc_cua;
109 
110 	struct timeout		sc_diag_tmo;
111 	int			sc_overflows;
112 	int			sc_floods;
113 	int			sc_errors;
114 
115 	int			sc_ibufs[2][CDUART_IBUFSIZE];
116 	int			*sc_ibuf;
117 	int			*sc_ibufend;
118 	int			*sc_ibufp;
119 };
120 
121 int	cduart_match(struct device *, void *, void *);
122 void	cduart_attach(struct device *, struct device *, void *);
123 void	cduart_diag(void *);
124 int	cduart_intr(void *);
125 void	cduart_softintr(void *);
126 
127 struct tty *cduarttty(dev_t);
128 struct cduart_softc *cduart_sc(dev_t);
129 
130 int	cduartparam(struct tty *, struct termios *);
131 void	cduartstart(struct tty *);
132 
133 int	cduartcnattach(bus_space_tag_t, bus_addr_t, int, tcflag_t);
134 void	cduartcnprobe(struct consdev *);
135 void	cduartcninit(struct consdev *);
136 int	cduartcngetc(dev_t);
137 void	cduartcnputc(dev_t, int);
138 void	cduartcnpollc(dev_t, int);
139 
140 cdev_decl(com);
141 cdev_decl(cduart);
142 
143 const struct cfattach cduart_ca = {
144 	sizeof(struct cduart_softc), cduart_match, cduart_attach
145 };
146 
147 struct cfdriver cduart_cd = {
148 	NULL, "cduart", DV_DULL
149 };
150 
151 bus_space_tag_t	cduartconsiot;
152 bus_space_handle_t cduartconsioh;
153 int		cduartconsrate;
154 tcflag_t	cduartconscflag;
155 struct cdevsw	cduartdev = cdev_tty_init(3, cduart);
156 
157 #define DEVUNIT(x)	(minor(x) & 0x7f)
158 #define DEVCUA(x)	(minor(x) & 0x80)
159 
160 static inline uint32_t
cduart_read(struct cduart_softc * sc,uint32_t reg)161 cduart_read(struct cduart_softc *sc, uint32_t reg)
162 {
163 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, reg);
164 }
165 
166 static inline void
cduart_write(struct cduart_softc * sc,uint32_t reg,uint32_t val)167 cduart_write(struct cduart_softc *sc, uint32_t reg, uint32_t val)
168 {
169 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
170 }
171 
172 void
cduart_init_cons(void)173 cduart_init_cons(void)
174 {
175 	struct fdt_reg reg;
176 	void *node;
177 
178 	if ((node = fdt_find_cons("cdns,uart-r1p8")) == NULL &&
179 	    (node = fdt_find_cons("cdns,uart-r1p12")) == NULL)
180 		return;
181 	if (fdt_get_reg(node, 0, &reg) != 0)
182 		return;
183 
184 	cduartcnattach(fdt_cons_bs_tag, reg.addr, B115200, TTYDEF_CFLAG);
185 }
186 
187 int
cduart_match(struct device * parent,void * match,void * aux)188 cduart_match(struct device *parent, void *match, void *aux)
189 {
190 	struct fdt_attach_args *faa = aux;
191 
192 	return OF_is_compatible(faa->fa_node, "cdns,uart-r1p8") ||
193 	    OF_is_compatible(faa->fa_node, "cdns,uart-r1p12");
194 }
195 
196 void
cduart_attach(struct device * parent,struct device * self,void * aux)197 cduart_attach(struct device *parent, struct device *self, void *aux)
198 {
199 	struct fdt_attach_args *faa = aux;
200 	struct cduart_softc *sc = (struct cduart_softc *)self;
201 	uint32_t cr, isr;
202 	int maj;
203 
204 	if (faa->fa_nreg < 1) {
205 		printf(": no registers\n");
206 		return;
207 	}
208 
209 	sc->sc_iot = faa->fa_iot;
210 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
211 	    faa->fa_reg[0].size, 0, &sc->sc_ioh) != 0) {
212 		printf(": can't map registers\n");
213 		return;
214 	}
215 
216 	/* Disable all interrupts. */
217 	cduart_write(sc, CDUART_IDR, ~0U);
218 
219 	/* Clear any pending interrupts. */
220 	isr = cduart_read(sc, CDUART_ISR);
221 	cduart_write(sc, CDUART_ISR, isr);
222 
223 	sc->sc_ih = fdt_intr_establish_idx(faa->fa_node, 0, IPL_TTY,
224 	    cduart_intr, sc, sc->sc_dev.dv_xname);
225 	if (sc->sc_ih == NULL) {
226 		printf(": can't establish interrupt\n");
227 		goto fail;
228 	}
229 
230 	timeout_set(&sc->sc_diag_tmo, cduart_diag, sc);
231 	sc->sc_si = softintr_establish(IPL_TTY, cduart_softintr, sc);
232 	if (sc->sc_si == NULL) {
233 		printf(": can't establish soft interrupt\n");
234 		goto fail;
235 	}
236 
237 	if (faa->fa_node == stdout_node) {
238 		/* Locate the major number. */
239 		for (maj = 0; maj < nchrdev; maj++) {
240 			if (cdevsw[maj].d_open == cduartopen)
241 				break;
242 		}
243 		KASSERT(maj < nchrdev);
244 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
245 		printf(": console");
246 	}
247 
248 	/* Enable transmitter and receiver. */
249 	cr = cduart_read(sc, CDUART_CR);
250 	cr &= ~(CDUART_CR_TXDIS | CDUART_CR_RXDIS);
251 	cr |= CDUART_CR_TXEN | CDUART_CR_RXEN;
252 	cduart_write(sc, CDUART_CR, cr);
253 
254 	printf("\n");
255 
256 	return;
257 
258 fail:
259 	if (sc->sc_si != NULL)
260 		softintr_disestablish(sc->sc_si);
261 	if (sc->sc_ih != NULL)
262 		fdt_intr_disestablish(sc->sc_ih);
263 	if (sc->sc_ioh != 0)
264 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, CDUART_SPACE_SIZE);
265 }
266 
267 int
cduart_intr(void * arg)268 cduart_intr(void *arg)
269 {
270 	struct cduart_softc *sc = arg;
271 	struct tty *tp = sc->sc_tty;
272 	int *ibufp;
273 	uint32_t isr, sr;
274 	int c, handled = 0;
275 
276 	if (tp == NULL)
277 		return 0;
278 
279 	isr = cduart_read(sc, CDUART_ISR);
280 	cduart_write(sc, CDUART_ISR, isr);
281 
282 	if ((isr & CDUART_IXR_TXEMPTY) && (tp->t_state & TS_BUSY)) {
283 		tp->t_state &= ~TS_BUSY;
284 		(*linesw[tp->t_line].l_start)(tp);
285 		handled = 1;
286 	}
287 
288 	if (isr & (CDUART_IXR_TOUT | CDUART_IXR_RTRIG)) {
289 		ibufp = sc->sc_ibufp;
290 		for (;;) {
291 			sr = cduart_read(sc, CDUART_SR);
292 			if (sr & CDUART_SR_RXEMPTY)
293 				break;
294 			c = cduart_read(sc, CDUART_FIFO) & 0xff;
295 
296 			if (ibufp < sc->sc_ibufend) {
297 				*ibufp++ = c;
298 			} else {
299 				sc->sc_floods++;
300 				if (sc->sc_errors++ == 0)
301 					timeout_add_sec(&sc->sc_diag_tmo, 60);
302 			}
303 		}
304 		if (sc->sc_ibufp != ibufp) {
305 			sc->sc_ibufp = ibufp;
306 			softintr_schedule(sc->sc_si);
307 		}
308 		handled = 1;
309 	}
310 
311 	if (isr & CDUART_IXR_RXOVR) {
312 		sc->sc_overflows++;
313 		if (sc->sc_errors++ == 0)
314 			timeout_add_sec(&sc->sc_diag_tmo, 60);
315 		handled = 1;
316 	}
317 
318 	return handled;
319 }
320 
321 void
cduart_softintr(void * arg)322 cduart_softintr(void *arg)
323 {
324 	struct cduart_softc *sc = arg;
325 	struct tty *tp = sc->sc_tty;
326 	int *ibufend, *ibufp;
327 	int s;
328 
329 	s = spltty();
330 
331 	ibufp = sc->sc_ibuf;
332 	ibufend = sc->sc_ibufp;
333 
334 	if (ibufp == ibufend) {
335 		splx(s);
336 		return;
337 	}
338 
339 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
340 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
341 	sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
342 
343 	if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0) {
344 		splx(s);
345 		return;
346 	}
347 
348 	splx(s);
349 
350 	while (ibufp < ibufend)
351 		(*linesw[tp->t_line].l_rint)(*ibufp++, tp);
352 }
353 
354 void
cduart_diag(void * arg)355 cduart_diag(void *arg)
356 {
357 	struct cduart_softc *sc = arg;
358 	int overflows, floods;
359 	int s;
360 
361 	s = spltty();
362 	sc->sc_errors = 0;
363 	overflows = sc->sc_overflows;
364 	sc->sc_overflows = 0;
365 	floods = sc->sc_floods;
366 	sc->sc_floods = 0;
367 	splx(s);
368 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
369 	    sc->sc_dev.dv_xname,
370 	    overflows, overflows == 1 ? "" : "s",
371 	    floods, floods == 1 ? "" : "s");
372 }
373 
374 int
cduartopen(dev_t dev,int flag,int mode,struct proc * p)375 cduartopen(dev_t dev, int flag, int mode, struct proc *p)
376 {
377 	struct cduart_softc *sc;
378 	struct tty *tp;
379 	uint32_t sr;
380 	int error, s;
381 
382 	sc = cduart_sc(dev);
383 	if (sc == NULL)
384 		return ENXIO;
385 
386 	s = spltty();
387 
388 	if (sc->sc_tty == NULL)
389 		sc->sc_tty = ttymalloc(0);
390 
391 	tp = sc->sc_tty;
392 	tp->t_oproc = cduartstart;
393 	tp->t_param = cduartparam;
394 	tp->t_dev = dev;
395 	if ((tp->t_state & TS_ISOPEN) == 0) {
396 		tp->t_state |= TS_WOPEN | TS_CARR_ON;
397 		ttychars(tp);
398 		tp->t_iflag = TTYDEF_IFLAG;
399 		tp->t_oflag = TTYDEF_OFLAG;
400 		tp->t_cflag = TTYDEF_CFLAG;
401 		tp->t_lflag = TTYDEF_LFLAG;
402 		tp->t_ispeed = B115200; /* XXX */
403 		tp->t_ospeed = tp->t_ispeed;
404 		ttsetwater(tp);
405 
406 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
407 		sc->sc_ibufend = sc->sc_ibuf + CDUART_IBUFSIZE;
408 
409 		cduart_write(sc, CDUART_RXTOUT, 10);
410 		cduart_write(sc, CDUART_RXWM, CDUART_FIFOSIZE / 2);
411 
412 		/* Clear any pending I/O. */
413 		for (;;) {
414 			sr = cduart_read(sc, CDUART_SR);
415 			if (sr & CDUART_SR_RXEMPTY)
416 				break;
417 			(void)cduart_read(sc, CDUART_FIFO);
418 		}
419 
420 		cduart_write(sc, CDUART_IER,
421 		    CDUART_IXR_TOUT | CDUART_IXR_RXOVR | CDUART_IXR_RTRIG);
422 	} else if ((tp->t_state & TS_XCLUDE) && suser(p) != 0) {
423 		splx(s);
424 		return EBUSY;
425 	}
426 
427 	if (DEVCUA(dev)) {
428 		if (tp->t_state & TS_ISOPEN) {
429 			splx(s);
430 			return EBUSY;
431 		}
432 		sc->sc_cua = 1;
433 	} else {
434 		if ((flag & O_NONBLOCK) && sc->sc_cua) {
435 			splx(s);
436 			return EBUSY;
437 		} else {
438 			while (sc->sc_cua) {
439 				tp->t_state |= TS_WOPEN;
440 				error = ttysleep(tp, &tp->t_rawq,
441 				    TTIPRI | PCATCH, ttopen);
442 				if (error != 0 && (tp->t_state & TS_WOPEN)) {
443 					tp->t_state &= ~TS_WOPEN;
444 					splx(s);
445 					return error;
446 				}
447 			}
448 		}
449 	}
450 
451 	splx(s);
452 
453 	return (*linesw[tp->t_line].l_open)(dev, tp, p);
454 }
455 
456 int
cduartclose(dev_t dev,int flag,int mode,struct proc * p)457 cduartclose(dev_t dev, int flag, int mode, struct proc *p)
458 {
459 	struct cduart_softc *sc;
460 	struct tty *tp;
461 	int s;
462 
463 	sc = cduart_sc(dev);
464 	tp = sc->sc_tty;
465 
466 	if ((tp->t_state & TS_ISOPEN) == 0)
467 		return 0;
468 
469 	(*linesw[tp->t_line].l_close)(tp, flag, p);
470 	s = spltty();
471 	/* Disable interrupts. */
472 	cduart_write(sc, CDUART_IDR, ~0U);
473 	sc->sc_cua = 0;
474 	splx(s);
475 	ttyclose(tp);
476 
477 	return 0;
478 }
479 
480 int
cduartread(dev_t dev,struct uio * uio,int flag)481 cduartread(dev_t dev, struct uio *uio, int flag)
482 {
483 	struct tty *tp;
484 
485 	tp = cduarttty(dev);
486 	if (tp == NULL)
487 		return ENODEV;
488 
489 	return (*linesw[tp->t_line].l_read)(tp, uio, flag);
490 }
491 
492 int
cduartwrite(dev_t dev,struct uio * uio,int flag)493 cduartwrite(dev_t dev, struct uio *uio, int flag)
494 {
495 	struct tty *tp;
496 
497 	tp = cduarttty(dev);
498 	if (tp == NULL)
499 		return ENODEV;
500 
501 	return (*linesw[tp->t_line].l_write)(tp, uio, flag);
502 }
503 
504 int
cduartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)505 cduartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
506 {
507 	struct cduart_softc *sc;
508 	struct tty *tp;
509 	int error;
510 
511 	sc = cduart_sc(dev);
512 	if (sc == NULL)
513 		return ENODEV;
514 
515 	tp = sc->sc_tty;
516 	if (tp == NULL)
517 		return ENXIO;
518 
519 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
520 	if (error >= 0)
521 		return error;
522 
523 	error = ttioctl(tp, cmd, data, flag, p);
524 	if (error >= 0)
525 		return error;
526 
527 	/* XXX */
528 	switch (cmd) {
529 	case TIOCSBRK:
530 	case TIOCCBRK:
531 	case TIOCSDTR:
532 	case TIOCCDTR:
533 	case TIOCMSET:
534 	case TIOCMBIC:
535 	case TIOCMGET:
536 	case TIOCGFLAGS:
537 		break;
538 	case TIOCSFLAGS:
539 		error = suser(p);
540 		if (error != 0)
541 			return EPERM;
542 		break;
543 	default:
544 		return ENOTTY;
545 	}
546 
547 	return 0;
548 }
549 
550 int
cduartparam(struct tty * tp,struct termios * t)551 cduartparam(struct tty *tp, struct termios *t)
552 {
553 	return 0;
554 }
555 
556 void
cduartstart(struct tty * tp)557 cduartstart(struct tty *tp)
558 {
559 	struct cduart_softc *sc;
560 	uint32_t sr;
561 	int s;
562 
563 	sc = cduart_sc(tp->t_dev);
564 
565 	s = spltty();
566 	if (tp->t_state & TS_BUSY)
567 		goto out;
568 	if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP))
569 		goto stopped;
570 	ttwakeupwr(tp);
571 	if (tp->t_outq.c_cc == 0)
572 		goto stopped;
573 	tp->t_state |= TS_BUSY;
574 
575 	cduart_write(sc, CDUART_ISR, CDUART_IXR_TXEMPTY);
576 
577 	sr = cduart_read(sc, CDUART_SR);
578 	while ((sr & CDUART_SR_TXFULL) == 0 && tp->t_outq.c_cc != 0) {
579 		cduart_write(sc, CDUART_FIFO, getc(&tp->t_outq));
580 		sr = cduart_read(sc, CDUART_SR);
581 	}
582 
583 	cduart_write(sc, CDUART_IER, CDUART_IXR_TXEMPTY);
584 out:
585 	splx(s);
586 	return;
587 stopped:
588 	cduart_write(sc, CDUART_IDR, CDUART_IXR_TXEMPTY);
589 	splx(s);
590 }
591 
592 int
cduartstop(struct tty * tp,int flag)593 cduartstop(struct tty *tp, int flag)
594 {
595 	return 0;
596 }
597 
598 struct tty *
cduarttty(dev_t dev)599 cduarttty(dev_t dev)
600 {
601 	struct cduart_softc *sc;
602 
603 	sc = cduart_sc(dev);
604 	if (sc == NULL)
605 		return NULL;
606 
607 	return sc->sc_tty;
608 }
609 
610 struct cduart_softc *
cduart_sc(dev_t dev)611 cduart_sc(dev_t dev)
612 {
613 	int unit = DEVUNIT(dev);
614 
615 	if (unit >= cduart_cd.cd_ndevs)
616 		return NULL;
617 	return (struct cduart_softc *)cduart_cd.cd_devs[unit];
618 }
619 
620 struct consdev cduartcons = {
621 	.cn_probe	= NULL,
622 	.cn_init	= NULL,
623 	.cn_getc	= cduartcngetc,
624 	.cn_putc	= cduartcnputc,
625 	.cn_pollc	= cduartcnpollc,
626 	.cn_bell	= NULL,
627 	.cn_dev		= NODEV,
628 	.cn_pri		= CN_MIDPRI,
629 };
630 
631 int
cduartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)632 cduartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
633     tcflag_t cflag)
634 {
635 	bus_space_handle_t ioh;
636 	int maj;
637 
638 	/* Look for major of com(4) to replace. */
639 	for (maj = 0; maj < nchrdev; maj++) {
640 		if (cdevsw[maj].d_open == comopen)
641 			break;
642 	}
643 	if (maj == nchrdev)
644 		return ENXIO;
645 
646 	if (bus_space_map(iot, iobase, CDUART_SPACE_SIZE, 0, &ioh) != 0)
647 		return ENOMEM;
648 
649 	cn_tab = &cduartcons;
650 	cn_tab->cn_dev = makedev(maj, 0);
651 	cdevsw[maj] = cduartdev;
652 
653 	cduartconsiot = iot;
654 	cduartconsioh = ioh;
655 	cduartconsrate = rate;
656 	cduartconscflag = cflag;
657 
658 	return 0;
659 }
660 
661 void
cduartcnprobe(struct consdev * cp)662 cduartcnprobe(struct consdev *cp)
663 {
664 }
665 
666 void
cduartcninit(struct consdev * cp)667 cduartcninit(struct consdev *cp)
668 {
669 }
670 
671 int
cduartcngetc(dev_t dev)672 cduartcngetc(dev_t dev)
673 {
674 	int s;
675 	uint8_t c;
676 
677 	s = splhigh();
678 	while (bus_space_read_4(cduartconsiot, cduartconsioh,
679 	    CDUART_SR) & CDUART_SR_RXEMPTY)
680 		CPU_BUSY_CYCLE();
681 	c = bus_space_read_4(cduartconsiot, cduartconsioh, CDUART_FIFO);
682 	splx(s);
683 
684 	return c;
685 }
686 
687 void
cduartcnputc(dev_t dev,int c)688 cduartcnputc(dev_t dev, int c)
689 {
690 	int s;
691 
692 	s = splhigh();
693 	while (bus_space_read_4(cduartconsiot, cduartconsioh,
694 	    CDUART_SR) & CDUART_SR_TXFULL)
695 		CPU_BUSY_CYCLE();
696 	bus_space_write_4(cduartconsiot, cduartconsioh, CDUART_FIFO, c);
697 	splx(s);
698 }
699 
700 void
cduartcnpollc(dev_t dev,int on)701 cduartcnpollc(dev_t dev, int on)
702 {
703 }
704