xref: /openbsd/sys/dev/ic/pluart.c (revision 1525749f)
1 /*	$OpenBSD: pluart.c,v 1.14 2022/07/02 08:50:42 visa Exp $	*/
2 /*
3  * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se>
4  * Copyright (c) 2005 Dale Rahn <drahn@dalerahn.com>
5  *
6  * Permission to use, copy, modify, and 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 #include <sys/param.h>
20 #include <sys/ioctl.h>
21 #include <sys/proc.h>
22 #include <sys/tty.h>
23 #include <sys/uio.h>
24 #include <sys/systm.h>
25 #include <sys/time.h>
26 #include <sys/device.h>
27 #include <sys/syslog.h>
28 #include <sys/conf.h>
29 #include <sys/fcntl.h>
30 #include <sys/kernel.h>
31 
32 #include <machine/bus.h>
33 
34 #include <dev/ic/pluartvar.h>
35 #include <dev/cons.h>
36 
37 #ifdef DDB
38 #include <ddb/db_var.h>
39 #endif
40 
41 #define DEVUNIT(x)      (minor(x) & 0x7f)
42 #define DEVCUA(x)       (minor(x) & 0x80)
43 
44 #define UART_DR			0x00		/* Data register */
45 #define UART_DR_DATA(x)		((x) & 0xf)
46 #define UART_DR_FE		(1 << 8)	/* Framing error */
47 #define UART_DR_PE		(1 << 9)	/* Parity error */
48 #define UART_DR_BE		(1 << 10)	/* Break error */
49 #define UART_DR_OE		(1 << 11)	/* Overrun error */
50 #define UART_RSR		0x04		/* Receive status register */
51 #define UART_RSR_FE		(1 << 0)	/* Framing error */
52 #define UART_RSR_PE		(1 << 1)	/* Parity error */
53 #define UART_RSR_BE		(1 << 2)	/* Break error */
54 #define UART_RSR_OE		(1 << 3)	/* Overrun error */
55 #define UART_ECR		0x04		/* Error clear register */
56 #define UART_ECR_FE		(1 << 0)	/* Framing error */
57 #define UART_ECR_PE		(1 << 1)	/* Parity error */
58 #define UART_ECR_BE		(1 << 2)	/* Break error */
59 #define UART_ECR_OE		(1 << 3)	/* Overrun error */
60 #define UART_FR			0x18		/* Flag register */
61 #define UART_FR_CTS		(1 << 0)	/* Clear to send */
62 #define UART_FR_DSR		(1 << 1)	/* Data set ready */
63 #define UART_FR_DCD		(1 << 2)	/* Data carrier detect */
64 #define UART_FR_BUSY		(1 << 3)	/* UART busy */
65 #define UART_FR_RXFE		(1 << 4)	/* Receive FIFO empty */
66 #define UART_FR_TXFF		(1 << 5)	/* Transmit FIFO full */
67 #define UART_FR_RXFF		(1 << 6)	/* Receive FIFO full */
68 #define UART_FR_TXFE		(1 << 7)	/* Transmit FIFO empty */
69 #define UART_FR_RI		(1 << 8)	/* Ring indicator */
70 #define UART_ILPR		0x20		/* IrDA low-power counter register */
71 #define UART_ILPR_ILPDVSR	((x) & 0xf)	/* IrDA low-power divisor */
72 #define UART_IBRD		0x24		/* Integer baud rate register */
73 #define UART_IBRD_DIVINT(x)	((x) & 0xffff)	/* Integer baud rate divisor */
74 #define UART_FBRD		0x28		/* Fractional baud rate register */
75 #define UART_FBRD_DIVFRAC(x)	((x) & 0x3f)	/* Fractional baud rate divisor */
76 #define UART_LCR_H		0x2c		/* Line control register */
77 #define UART_LCR_H_BRK		(1 << 0)	/* Send break */
78 #define UART_LCR_H_PEN		(1 << 1)	/* Parity enable */
79 #define UART_LCR_H_EPS		(1 << 2)	/* Even parity select */
80 #define UART_LCR_H_STP2		(1 << 3)	/* Two stop bits select */
81 #define UART_LCR_H_FEN		(1 << 4)	/* Enable FIFOs */
82 #define UART_LCR_H_WLEN5	(0x0 << 5)	/* Word length: 5 bits */
83 #define UART_LCR_H_WLEN6	(0x1 << 5)	/* Word length: 6 bits */
84 #define UART_LCR_H_WLEN7	(0x2 << 5)	/* Word length: 7 bits */
85 #define UART_LCR_H_WLEN8	(0x3 << 5)	/* Word length: 8 bits */
86 #define UART_LCR_H_SPS		(1 << 7)	/* Stick parity select */
87 #define UART_CR			0x30		/* Control register */
88 #define UART_CR_UARTEN		(1 << 0)	/* UART enable */
89 #define UART_CR_SIREN		(1 << 1)	/* SIR enable */
90 #define UART_CR_SIRLP		(1 << 2)	/* IrDA SIR low power mode */
91 #define UART_CR_LBE		(1 << 7)	/* Loop back enable */
92 #define UART_CR_TXE		(1 << 8)	/* Transmit enable */
93 #define UART_CR_RXE		(1 << 9)	/* Receive enable */
94 #define UART_CR_DTR		(1 << 10)	/* Data transmit enable */
95 #define UART_CR_RTS		(1 << 11)	/* Request to send */
96 #define UART_CR_OUT1		(1 << 12)
97 #define UART_CR_OUT2		(1 << 13)
98 #define UART_CR_CTSE		(1 << 14)	/* CTS hardware flow control enable */
99 #define UART_CR_RTSE		(1 << 15)	/* RTS hardware flow control enable */
100 #define UART_IFLS		0x34		/* Interrupt FIFO level select register */
101 #define UART_IFLS_RX_SHIFT	3		/* RX level in bits [5:3] */
102 #define UART_IFLS_TX_SHIFT	0		/* TX level in bits [2:0] */
103 #define UART_IFLS_1_8		0		/* FIFO 1/8 full */
104 #define UART_IFLS_1_4		1		/* FIFO 1/4 full */
105 #define UART_IFLS_1_2		2		/* FIFO 1/2 full */
106 #define UART_IFLS_3_4		3		/* FIFO 3/4 full */
107 #define UART_IFLS_7_8		4		/* FIFO 7/8 full */
108 #define UART_IMSC		0x38		/* Interrupt mask set/clear register */
109 #define UART_IMSC_RIMIM		(1 << 0)
110 #define UART_IMSC_CTSMIM	(1 << 1)
111 #define UART_IMSC_DCDMIM	(1 << 2)
112 #define UART_IMSC_DSRMIM	(1 << 3)
113 #define UART_IMSC_RXIM		(1 << 4)
114 #define UART_IMSC_TXIM		(1 << 5)
115 #define UART_IMSC_RTIM		(1 << 6)
116 #define UART_IMSC_FEIM		(1 << 7)
117 #define UART_IMSC_PEIM		(1 << 8)
118 #define UART_IMSC_BEIM		(1 << 9)
119 #define UART_IMSC_OEIM		(1 << 10)
120 #define UART_RIS		0x3c		/* Raw interrupt status register */
121 #define UART_MIS		0x40		/* Masked interrupt status register */
122 #define UART_ICR		0x44		/* Interrupt clear register */
123 #define UART_DMACR		0x48		/* DMA control register */
124 #define UART_PID0		0xfe0		/* Peripheral identification register 0 */
125 #define UART_PID1		0xfe4		/* Peripheral identification register 1 */
126 #define UART_PID2		0xfe8		/* Peripheral identification register 2 */
127 #define UART_PID2_REV(x)	(((x) & 0xf0) >> 4)
128 #define UART_PID3		0xfec		/* Peripheral identification register 3 */
129 #define UART_SPACE		0x100
130 
131 #define UART_FIFO_SIZE		16
132 #define UART_FIFO_SIZE_R3	32
133 
134 void pluartcnprobe(struct consdev *cp);
135 void pluartcninit(struct consdev *cp);
136 int pluartcngetc(dev_t dev);
137 void pluartcnputc(dev_t dev, int c);
138 void pluartcnpollc(dev_t dev, int on);
139 int  pluart_param(struct tty *tp, struct termios *t);
140 void pluart_start(struct tty *);
141 void pluart_diag(void *arg);
142 void pluart_raisedtr(void *arg);
143 void pluart_softint(void *arg);
144 struct pluart_softc *pluart_sc(dev_t dev);
145 
146 /* XXX - we imitate 'com' serial ports and take over their entry points */
147 /* XXX: These belong elsewhere */
148 cdev_decl(com);
149 cdev_decl(pluart);
150 
151 struct cfdriver pluart_cd = {
152 	NULL, "pluart", DV_TTY
153 };
154 
155 int		pluartdefaultrate = B38400;
156 int		pluartconsrate = B38400;
157 bus_space_tag_t	pluartconsiot;
158 bus_space_handle_t pluartconsioh;
159 bus_addr_t	pluartconsaddr;
160 tcflag_t	pluartconscflag = TTYDEF_CFLAG;
161 
162 struct cdevsw pluartdev =
163 	cdev_tty_init(3/*XXX NUART */ ,pluart);		/* 12: serial port */
164 
165 void
pluart_attach_common(struct pluart_softc * sc,int console)166 pluart_attach_common(struct pluart_softc *sc, int console)
167 {
168 	int fifolen, fr, lcr, maj;
169 
170 	if ((sc->sc_hwflags & COM_HW_SBSA) == 0) {
171 		if (sc->sc_hwrev == 0)
172 			sc->sc_hwrev = UART_PID2_REV(bus_space_read_4(sc->sc_iot,
173 			    sc->sc_ioh, UART_PID2));
174 		if (sc->sc_hwrev < 3)
175 			fifolen = UART_FIFO_SIZE;
176 		else
177 			fifolen = UART_FIFO_SIZE_R3;
178 		printf(": rev %d, %d byte fifo\n", sc->sc_hwrev, fifolen);
179 	} else {
180 		/*
181 		 * The SBSA UART is PL011 r1p5 compliant which implies revision
182 		 * 3 with a 32 byte FIFO. However, we cannot expect to configure
183 		 * RX/TX interrupt levels using the UARTIFLS register making it
184 		 * impossible to make assumptions about the number of available
185 		 * bytes in the FIFO. Therefore disable FIFO support for such
186 		 * devices.
187 		 */
188 		fifolen = 0;
189 		printf("\n");
190 	}
191 
192 	if (console) {
193 		/* Locate the major number. */
194 		for (maj = 0; maj < nchrdev; maj++)
195 			if (cdevsw[maj].d_open == pluartopen)
196 				break;
197 		cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
198 
199 		printf("%s: console\n", sc->sc_dev.dv_xname);
200 		SET(sc->sc_hwflags, COM_HW_CONSOLE);
201 	}
202 
203 	timeout_set(&sc->sc_diag_tmo, pluart_diag, sc);
204 	timeout_set(&sc->sc_dtr_tmo, pluart_raisedtr, sc);
205 	sc->sc_si = softintr_establish(IPL_TTY, pluart_softint, sc);
206 
207 	if(sc->sc_si == NULL)
208 		panic("%s: can't establish soft interrupt.",
209 		    sc->sc_dev.dv_xname);
210 
211 	/* Flush transmit before enabling FIFO. */
212 	for (;;) {
213 		fr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_FR);
214 		if (fr & UART_FR_TXFE)
215 			break;
216 		delay(100);
217 	}
218 
219 	if (fifolen > 0) {
220 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS,
221 		    (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) |
222 		    (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT));
223 	}
224 	sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM;
225 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc);
226 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff);
227 
228 
229 	lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
230 	if (fifolen > 0)
231 		lcr |= UART_LCR_H_FEN;
232 	else
233 		lcr &= ~UART_LCR_H_FEN;
234 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
235 }
236 
237 int
pluart_intr(void * arg)238 pluart_intr(void *arg)
239 {
240 	struct pluart_softc *sc = arg;
241 	bus_space_tag_t iot = sc->sc_iot;
242 	bus_space_handle_t ioh = sc->sc_ioh;
243 	struct tty *tp = sc->sc_tty;
244 	u_int16_t is;
245 	u_int16_t *p;
246 	u_int16_t c;
247 
248 	is = bus_space_read_4(iot, ioh, UART_MIS);
249 	bus_space_write_4(iot, ioh, UART_ICR, is & ~UART_IMSC_TXIM);
250 
251 	if (sc->sc_tty == NULL)
252 		return 0;
253 
254 	if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) &&
255 	    !ISSET(is, UART_IMSC_TXIM))
256 		return 0;
257 
258 	if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) {
259 		CLR(tp->t_state, TS_BUSY | TS_FLUSH);
260 		if (sc->sc_halt > 0)
261 			wakeup(&tp->t_outq);
262 		(*linesw[tp->t_line].l_start)(tp);
263 	}
264 
265 	p = sc->sc_ibufp;
266 
267 	while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) {
268 		c = bus_space_read_2(iot, ioh, UART_DR);
269 		if (c & UART_DR_BE) {
270 #ifdef DDB
271 			if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE)) {
272 				if (db_console)
273 					db_enter();
274 				continue;
275 			}
276 #endif
277 			c = 0;
278 		}
279 		if (p >= sc->sc_ibufend) {
280 			sc->sc_floods++;
281 			if (sc->sc_errors++ == 0)
282 				timeout_add_sec(&sc->sc_diag_tmo, 60);
283 		} else {
284 			*p++ = c;
285 			if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS)) {
286 				/* XXX */
287 				//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
288 				//bus_space_write_4(iot, ioh, IMXUART_UCR3,
289 				//    sc->sc_ucr3);
290 			}
291 		}
292 		/* XXX - msr stuff ? */
293 	}
294 	sc->sc_ibufp = p;
295 
296 	softintr_schedule(sc->sc_si);
297 
298 	return 1;
299 }
300 
301 int
pluart_param(struct tty * tp,struct termios * t)302 pluart_param(struct tty *tp, struct termios *t)
303 {
304 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
305 	int ospeed = t->c_ospeed;
306 	int error;
307 	tcflag_t oldcflag;
308 
309 	if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
310 		return EINVAL;
311 
312 	switch (ISSET(t->c_cflag, CSIZE)) {
313 	case CS5:
314 		return EINVAL;
315 	case CS6:
316 		return EINVAL;
317 	case CS7:
318 		//CLR(sc->sc_ucr2, IMXUART_CR2_WS);
319 		break;
320 	case CS8:
321 		//SET(sc->sc_ucr2, IMXUART_CR2_WS);
322 		break;
323 	}
324 //	bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
325 
326 	/*
327 	if (ISSET(t->c_cflag, PARENB)) {
328 		SET(sc->sc_ucr2, IMXUART_CR2_PREN);
329 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
330 	}
331 	*/
332 	/* STOPB - XXX */
333 	if (ospeed == 0) {
334 		/* lower dtr */
335 	}
336 
337 	if (sc->sc_clkfreq != 0 && ospeed != 0 && ospeed != tp->t_ospeed) {
338 		int cr, div, lcr;
339 
340 		while (ISSET(tp->t_state, TS_BUSY)) {
341 			++sc->sc_halt;
342 			error = ttysleep(tp, &tp->t_outq,
343 			    TTOPRI | PCATCH, "pluartprm");
344 			--sc->sc_halt;
345 			if (error) {
346 				pluart_start(tp);
347 				return (error);
348 			}
349 		}
350 
351 		/*
352 		 * Writes to IBRD and FBRD are made effective first when LCR_H
353 		 * is written.
354 		 */
355 		lcr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H);
356 
357 		/* The UART must be disabled while changing the baud rate. */
358 		cr = bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_CR);
359 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR,
360 		    cr & ~UART_CR_UARTEN);
361 
362 		/*
363 		 * The baud rate divisor is expressed relative to the UART clock
364 		 * frequency where IBRD represents the quotient using 16 bits
365 		 * and FBRD the remainder using 6 bits. The PL011 specification
366 		 * provides the following formula:
367 		 *
368 		 *	uartclk/(16 * baudrate)
369 		 *
370 		 * The formula can be estimated by scaling it with the
371 		 * precision 64 (2^6) and letting the resulting upper 16 bits
372 		 * represents the quotient and the lower 6 bits the remainder:
373 		 *
374 		 *	64 * uartclk/(16 * baudrate) = 4 * uartclk/baudrate
375 		 */
376 		div = 4 * sc->sc_clkfreq / ospeed;
377 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IBRD,
378 		    UART_IBRD_DIVINT(div >> 6));
379 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_FBRD,
380 		    UART_FBRD_DIVFRAC(div));
381 		/* Commit baud rate change. */
382 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, lcr);
383 		/* Enable UART. */
384 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_CR, cr);
385 	}
386 
387 	/* setup fifo */
388 
389 	/* When not using CRTSCTS, RTS follows DTR. */
390 	/* sc->sc_dtr = MCR_DTR; */
391 
392 	/* and copy to tty */
393 	tp->t_ispeed = t->c_ispeed;
394 	tp->t_ospeed = t->c_ospeed;
395 	oldcflag = tp->t_cflag;
396 	tp->t_cflag = t->c_cflag;
397 
398         /*
399 	 * If DCD is off and MDMBUF is changed, ask the tty layer if we should
400 	 * stop the device.
401 	 */
402 	 /* XXX */
403 
404 	pluart_start(tp);
405 
406 	return 0;
407 }
408 
409 void
pluart_start(struct tty * tp)410 pluart_start(struct tty *tp)
411 {
412 	struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)];
413 	bus_space_tag_t iot = sc->sc_iot;
414 	bus_space_handle_t ioh = sc->sc_ioh;
415 	int s;
416 
417 	s = spltty();
418 	if (ISSET(tp->t_state, TS_BUSY))
419 		goto out;
420 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
421 		goto stopped;
422 	ttwakeupwr(tp);
423 	if (tp->t_outq.c_cc == 0)
424 		goto stopped;
425 	SET(tp->t_state, TS_BUSY);
426 
427 	/* Enable transmit interrupt. */
428 	if (!ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
429 		sc->sc_imsc |= UART_IMSC_TXIM;
430 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
431 		    sc->sc_imsc);
432 	}
433 
434 	while (tp->t_outq.c_cc > 0) {
435 		uint16_t fr;
436 
437 		fr = bus_space_read_4(iot, ioh, UART_FR);
438 		if (ISSET(fr, UART_FR_TXFF))
439 			break;
440 
441 		bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq));
442 	}
443 
444 out:
445 	splx(s);
446 	return;
447 
448 stopped:
449 	/* Disable transmit interrupt. */
450 	if (ISSET(sc->sc_imsc, UART_IMSC_TXIM)) {
451 		sc->sc_imsc &= ~UART_IMSC_TXIM;
452 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC,
453 		    sc->sc_imsc);
454 	}
455 	splx(s);
456 }
457 
458 void
pluart_diag(void * arg)459 pluart_diag(void *arg)
460 {
461 	struct pluart_softc *sc = arg;
462 	int overflows, floods;
463 	int s;
464 
465 	s = spltty();
466 	sc->sc_errors = 0;
467 	overflows = sc->sc_overflows;
468 	sc->sc_overflows = 0;
469 	floods = sc->sc_floods;
470 	sc->sc_floods = 0;
471 	splx(s);
472 	log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
473 	    sc->sc_dev.dv_xname,
474 	    overflows, overflows == 1 ? "" : "s",
475 	    floods, floods == 1 ? "" : "s");
476 }
477 
478 void
pluart_raisedtr(void * arg)479 pluart_raisedtr(void *arg)
480 {
481 	//struct pluart_softc *sc = arg;
482 
483 	//SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
484 	//bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
485 }
486 
487 void
pluart_softint(void * arg)488 pluart_softint(void *arg)
489 {
490 	struct pluart_softc *sc = arg;
491 	struct tty *tp;
492 	u_int16_t *ibufp;
493 	u_int16_t *ibufend;
494 	int c;
495 	int err;
496 	int s;
497 
498 	if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
499 		return;
500 
501 	tp = sc->sc_tty;
502 	s = spltty();
503 
504 	ibufp = sc->sc_ibuf;
505 	ibufend = sc->sc_ibufp;
506 
507 	if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
508 		splx(s);
509 		return;
510 	}
511 
512 	sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
513 	    sc->sc_ibufs[1] : sc->sc_ibufs[0];
514 	sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
515 	sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
516 
517 #if 0
518 	if (ISSET(tp->t_cflag, CRTSCTS) &&
519 	    !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
520 		/* XXX */
521 		SET(sc->sc_ucr3, IMXUART_CR3_DSR);
522 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
523 		    sc->sc_ucr3);
524 	}
525 #endif
526 
527 	splx(s);
528 
529 	while (ibufp < ibufend) {
530 		c = *ibufp++;
531 		/*
532 		if (ISSET(c, IMXUART_RX_OVERRUN)) {
533 			sc->sc_overflows++;
534 			if (sc->sc_errors++ == 0)
535 				timeout_add_sec(&sc->sc_diag_tmo, 60);
536 		}
537 		*/
538 		/* This is ugly, but fast. */
539 
540 		err = 0;
541 		/*
542 		if (ISSET(c, IMXUART_RX_PRERR))
543 			err |= TTY_PE;
544 		if (ISSET(c, IMXUART_RX_FRMERR))
545 			err |= TTY_FE;
546 		*/
547 		c = (c & 0xff) | err;
548 		(*linesw[tp->t_line].l_rint)(c, tp);
549 	}
550 }
551 
552 int
pluartopen(dev_t dev,int flag,int mode,struct proc * p)553 pluartopen(dev_t dev, int flag, int mode, struct proc *p)
554 {
555 	int unit = DEVUNIT(dev);
556 	struct pluart_softc *sc;
557 	bus_space_tag_t iot;
558 	bus_space_handle_t ioh;
559 	struct tty *tp;
560 	int s;
561 	int error = 0;
562 
563 	if (unit >= pluart_cd.cd_ndevs)
564 		return ENXIO;
565 	sc = pluart_cd.cd_devs[unit];
566 	if (sc == NULL)
567 		return ENXIO;
568 
569 	s = spltty();
570 	if (sc->sc_tty == NULL)
571 		tp = sc->sc_tty = ttymalloc(0);
572 	else
573 		tp = sc->sc_tty;
574 
575 	splx(s);
576 
577 	tp->t_oproc = pluart_start;
578 	tp->t_param = pluart_param;
579 	tp->t_dev = dev;
580 
581 	if (!ISSET(tp->t_state, TS_ISOPEN)) {
582 		SET(tp->t_state, TS_WOPEN);
583 		ttychars(tp);
584 		tp->t_iflag = TTYDEF_IFLAG;
585 		tp->t_oflag = TTYDEF_OFLAG;
586 
587 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
588 			tp->t_cflag = pluartconscflag;
589 		else
590 			tp->t_cflag = TTYDEF_CFLAG;
591 		if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
592 			SET(tp->t_cflag, CLOCAL);
593 		if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
594 			SET(tp->t_cflag, CRTSCTS);
595 		if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
596 			SET(tp->t_cflag, MDMBUF);
597 		tp->t_lflag = TTYDEF_LFLAG;
598 		if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
599 			tp->t_ispeed = tp->t_ospeed = pluartconsrate;
600 		else
601 			tp->t_ispeed = tp->t_ospeed = pluartdefaultrate;
602 
603 		s = spltty();
604 
605 		sc->sc_initialize = 1;
606 		pluart_param(tp, &tp->t_termios);
607 		ttsetwater(tp);
608 		sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
609 		sc->sc_ibufhigh = sc->sc_ibuf + UART_IHIGHWATER;
610 		sc->sc_ibufend = sc->sc_ibuf + UART_IBUFSIZE;
611 
612 		iot = sc->sc_iot;
613 		ioh = sc->sc_ioh;
614 
615 #if 0
616 		sc->sc_ucr1 = bus_space_read_4(iot, ioh, IMXUART_UCR1);
617 		sc->sc_ucr2 = bus_space_read_4(iot, ioh, IMXUART_UCR2);
618 		sc->sc_ucr3 = bus_space_read_4(iot, ioh, IMXUART_UCR3);
619 		sc->sc_ucr4 = bus_space_read_4(iot, ioh, IMXUART_UCR4);
620 
621 		/* interrupt after one char on tx/rx */
622 		/* reference frequency divider: 1 */
623 		bus_space_write_4(iot, ioh, IMXUART_UFCR,
624 		    1 << IMXUART_FCR_TXTL_SH |
625 		    5 << IMXUART_FCR_RFDIV_SH |
626 		    1 << IMXUART_FCR_RXTL_SH);
627 
628 		SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
629 		SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
630 		bus_space_write_4(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
631 		bus_space_write_4(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
632 
633 		/* sc->sc_mcr = MCR_DTR | MCR_RTS;  XXX */
634 		SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
635 		bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
636 #endif
637 
638 		SET(tp->t_state, TS_CARR_ON); /* XXX */
639 
640 
641 	} else if (ISSET(tp->t_state, TS_XCLUDE) && suser(p) != 0)
642 		return EBUSY;
643 	else
644 		s = spltty();
645 
646 	if (DEVCUA(dev)) {
647 		if (ISSET(tp->t_state, TS_ISOPEN)) {
648 			splx(s);
649 			return EBUSY;
650 		}
651 		sc->sc_cua = 1;
652 	} else {
653 		/* tty (not cua) device; wait for carrier if necessary */
654 		if (ISSET(flag, O_NONBLOCK)) {
655 			if (sc->sc_cua) {
656 				/* Opening TTY non-blocking... but the CUA is busy */
657 				splx(s);
658 				return EBUSY;
659 			}
660 		} else {
661 			while (sc->sc_cua ||
662 			    (!ISSET(tp->t_cflag, CLOCAL) &&
663 				!ISSET(tp->t_state, TS_CARR_ON))) {
664 				SET(tp->t_state, TS_WOPEN);
665 				error = ttysleep(tp, &tp->t_rawq,
666 				    TTIPRI | PCATCH, ttopen);
667 				/*
668 				 * If TS_WOPEN has been reset, that means the
669 				 * cua device has been closed.  We don't want
670 				 * to fail in that case,
671 				 * so just go around again.
672 				 */
673 				if (error && ISSET(tp->t_state, TS_WOPEN)) {
674 					CLR(tp->t_state, TS_WOPEN);
675 					splx(s);
676 					return error;
677 				}
678 			}
679 		}
680 	}
681 	splx(s);
682 	return (*linesw[tp->t_line].l_open)(dev,tp,p);
683 }
684 
685 int
pluartclose(dev_t dev,int flag,int mode,struct proc * p)686 pluartclose(dev_t dev, int flag, int mode, struct proc *p)
687 {
688 	int unit = DEVUNIT(dev);
689 	struct pluart_softc *sc = pluart_cd.cd_devs[unit];
690 	//bus_space_tag_t iot = sc->sc_iot;
691 	//bus_space_handle_t ioh = sc->sc_ioh;
692 	struct tty *tp = sc->sc_tty;
693 	int s;
694 
695 	/* XXX This is for cons.c. */
696 	if (!ISSET(tp->t_state, TS_ISOPEN))
697 		return 0;
698 
699 	(*linesw[tp->t_line].l_close)(tp, flag, p);
700 	s = spltty();
701 	if (ISSET(tp->t_state, TS_WOPEN)) {
702 		/* tty device is waiting for carrier; drop dtr then re-raise */
703 		//CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
704 		//bus_space_write_4(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
705 		timeout_add_sec(&sc->sc_dtr_tmo, 2);
706 	}
707 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
708 
709 	sc->sc_cua = 0;
710 	splx(s);
711 	ttyclose(tp);
712 
713 	return 0;
714 }
715 
716 int
pluartread(dev_t dev,struct uio * uio,int flag)717 pluartread(dev_t dev, struct uio *uio, int flag)
718 {
719 	struct tty *tty;
720 
721 	tty = pluarttty(dev);
722 	if (tty == NULL)
723 		return ENODEV;
724 
725 	return((*linesw[tty->t_line].l_read)(tty, uio, flag));
726 }
727 
728 int
pluartwrite(dev_t dev,struct uio * uio,int flag)729 pluartwrite(dev_t dev, struct uio *uio, int flag)
730 {
731 	struct tty *tty;
732 
733 	tty = pluarttty(dev);
734 	if (tty == NULL)
735 		return ENODEV;
736 
737 	return((*linesw[tty->t_line].l_write)(tty, uio, flag));
738 }
739 
740 int
pluartioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)741 pluartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
742 {
743 	struct pluart_softc *sc;
744 	struct tty *tp;
745 	int error;
746 
747 	sc = pluart_sc(dev);
748 	if (sc == NULL)
749 		return (ENODEV);
750 
751 	tp = sc->sc_tty;
752 	if (tp == NULL)
753 		return (ENXIO);
754 
755 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
756 	if (error >= 0)
757 		return (error);
758 
759 	error = ttioctl(tp, cmd, data, flag, p);
760 	if (error >= 0)
761 		return (error);
762 
763 	switch(cmd) {
764 	case TIOCSBRK:
765 		break;
766 	case TIOCCBRK:
767 		break;
768 	case TIOCSDTR:
769 		break;
770 	case TIOCCDTR:
771 		break;
772 	case TIOCMSET:
773 		break;
774 	case TIOCMBIS:
775 		break;
776 	case TIOCMBIC:
777 		break;
778 	case TIOCMGET:
779 		break;
780 	case TIOCGFLAGS:
781 		break;
782 	case TIOCSFLAGS:
783 		error = suser(p);
784 		if (error != 0)
785 			return(EPERM);
786 		break;
787 	default:
788 		return (ENOTTY);
789 	}
790 
791 	return 0;
792 }
793 
794 int
pluartstop(struct tty * tp,int flag)795 pluartstop(struct tty *tp, int flag)
796 {
797 	return 0;
798 }
799 
800 struct tty *
pluarttty(dev_t dev)801 pluarttty(dev_t dev)
802 {
803 	int unit;
804 	struct pluart_softc *sc;
805 	unit = DEVUNIT(dev);
806 	if (unit >= pluart_cd.cd_ndevs)
807 		return NULL;
808 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
809 	if (sc == NULL)
810 		return NULL;
811 	return sc->sc_tty;
812 }
813 
814 struct pluart_softc *
pluart_sc(dev_t dev)815 pluart_sc(dev_t dev)
816 {
817 	int unit;
818 	struct pluart_softc *sc;
819 	unit = DEVUNIT(dev);
820 	if (unit >= pluart_cd.cd_ndevs)
821 		return NULL;
822 	sc = (struct pluart_softc *)pluart_cd.cd_devs[unit];
823 	return sc;
824 }
825 
826 
827 /* serial console */
828 void
pluartcnprobe(struct consdev * cp)829 pluartcnprobe(struct consdev *cp)
830 {
831 }
832 
833 void
pluartcninit(struct consdev * cp)834 pluartcninit(struct consdev *cp)
835 {
836 }
837 
838 int
pluartcnattach(bus_space_tag_t iot,bus_addr_t iobase,int rate,tcflag_t cflag)839 pluartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
840 {
841 	static struct consdev pluartcons = {
842 		NULL, NULL, pluartcngetc, pluartcnputc, pluartcnpollc, NULL,
843 		NODEV, CN_MIDPRI
844 	};
845 	int maj;
846 
847 	if (bus_space_map(iot, iobase, UART_SPACE, 0, &pluartconsioh))
848 		return ENOMEM;
849 
850 	/* Disable FIFO. */
851 	bus_space_write_4(iot, pluartconsioh, UART_LCR_H,
852 	    bus_space_read_4(iot, pluartconsioh, UART_LCR_H) & ~UART_LCR_H_FEN);
853 
854 	/* Look for major of com(4) to replace. */
855 	for (maj = 0; maj < nchrdev; maj++)
856 		if (cdevsw[maj].d_open == comopen)
857 			break;
858 	if (maj == nchrdev)
859 		return ENXIO;
860 
861 	cn_tab = &pluartcons;
862 	cn_tab->cn_dev = makedev(maj, 0);
863 	cdevsw[maj] = pluartdev;	/* KLUDGE */
864 
865 	pluartconsiot = iot;
866 	pluartconsaddr = iobase;
867 	pluartconscflag = cflag;
868 	pluartconsrate = rate;
869 
870 	return 0;
871 }
872 
873 int
pluartcngetc(dev_t dev)874 pluartcngetc(dev_t dev)
875 {
876 	int c;
877 	int s;
878 	s = splhigh();
879 	while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
880 	    UART_FR_RXFE))
881 		;
882 	c = bus_space_read_4(pluartconsiot, pluartconsioh, UART_DR);
883 	splx(s);
884 	return c;
885 }
886 
887 void
pluartcnputc(dev_t dev,int c)888 pluartcnputc(dev_t dev, int c)
889 {
890 	int s;
891 	s = splhigh();
892 	while ((bus_space_read_4(pluartconsiot, pluartconsioh, UART_FR) &
893 	    UART_FR_TXFF))
894 		;
895 	bus_space_write_4(pluartconsiot, pluartconsioh, UART_DR, (uint8_t)c);
896 	splx(s);
897 }
898 
899 void
pluartcnpollc(dev_t dev,int on)900 pluartcnpollc(dev_t dev, int on)
901 {
902 }
903