xref: /plan9-contrib/sys/src/9/vt4/uartlite.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1 /*
2  * Xilinx uartlite driver.
3  * uartlite has 16-byte fifos.
4  */
5 #include "u.h"
6 #include "../port/lib.h"
7 #include "mem.h"
8 #include "dat.h"
9 #include "fns.h"
10 #include "../port/error.h"
11 
12 #include "io.h"
13 
14 enum {
15 	/* control register bit positions */
16 	Ctlintrena	= 0x10,		/* enable interrupt */
17 	Rxfiforst	= 0x02,		/* reset receive FIFO */
18 	Txfiforst	= 0x01,		/* reset transmit FIFO */
19 
20 	/* status register bit positions */
21 	Parerr		= 0x80,
22 	Framerr		= 0x40,
23 	Overrunerr	= 0x20,
24 	Stsintrena	= 0x10,		/* interrupt enabled */
25 	Txfifofull	= 0x08,		/* transmit FIFO full */
26 	Txfifoempty	= 0x04,		/* transmit FIFO empty */
27 	Rxfifofull	= 0x02,		/* receive FIFO full */
28 	Rxfifohasdata	= 0x01,		/* data in receive FIFO */
29 };
30 
31 typedef struct Uartregs Uartregs;
32 struct Uartregs {
33 	ulong	rxfifo;
34 	ulong	txfifo;
35 	ulong	status;			/* read-only; read clears error bits */
36 	ulong	ctl;			/* write-only */
37 };
38 
39 typedef struct Ctlr {
40 	int	port;
41 	Uartregs *regs;
42 	int	irq;
43 	int	tbdf;
44 	int	iena;
45 	int	poll;
46 
47 	int	fena;
48 //	Rendez	xmitrend;
49 //	Rendez	rcvrend;
50 } Ctlr;
51 
52 extern PhysUart litephysuart;
53 
54 static Ctlr litectlr[1] = {
55 {
56 	.port = 0,
57 	.regs = (Uartregs *)Uartlite,
58 	.poll	= 0, },			/* was 1 */
59 };
60 
61 static Uart liteuart[1] = {
62 {	.regs	= &litectlr[0],
63 	.name	= "eia0",
64 	.phys	= &litephysuart,
65 	.special= 0,
66 	.next	= nil, },
67 };
68 
69 static int
canxmit(void * stsp)70 canxmit(void *stsp)
71 {
72 	return !(*(ulong *)stsp & Txfifofull);
73 }
74 
75 static int
canread(void * stsp)76 canread(void *stsp)
77 {
78 	return (*(ulong *)stsp & Rxfifohasdata) != 0;
79 }
80 
81 static long
litestatus(Uart * uart,void * buf,long n,long offset)82 litestatus(Uart* uart, void* buf, long n, long offset)
83 {
84 	char *p;
85 	Ctlr *ctlr;
86 
87 	ctlr = uart->regs;
88 	p = malloc(READSTR);
89 	snprint(p, READSTR,
90 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
91 		"dev(%d) type(%d) framing(%d) overruns(%d) "
92 		"berr(%d) serr(%d)%s%s%s%s\n",
93 
94 		uart->baud,
95 		uart->hup_dcd,
96 		0,
97 		uart->hup_dsr,
98 		8,
99 		0,
100 		'n',
101 		0,
102 		1,
103 		ctlr->fena,
104 
105 		uart->dev,
106 		uart->type,
107 		uart->ferr,
108 		uart->oerr,
109 		uart->berr,
110 		uart->serr,
111 		"",
112 		"",
113 		"",
114 		""
115 	);
116 	n = readstr(offset, buf, n, p);
117 	free(p);
118 	return n;
119 }
120 
121 #define litedtr litefifo
122 #define literts litefifo
123 #define litemodemctl litefifo
124 #define litebreak litefifo
125 
126 static void
litefifo(Uart *,int)127 litefifo(Uart*, int)
128 {
129 }
130 
131 #define litestop liteparity
132 #define litebits liteparity
133 #define litebaud liteparity
134 
135 static int
liteparity(Uart *,int)136 liteparity(Uart*, int)
137 {
138 	return 0;
139 }
140 
141 static void
litekick(Uart * uart)142 litekick(Uart* uart)
143 {
144 	Ctlr *ctlr;
145 	Uartregs *urp;
146 
147 	if(uart == nil || uart->blocked)
148 		return;
149 	ctlr = uart->regs;
150 	urp = ctlr->regs;
151 	while (!(urp->status & Txfifofull)) {
152 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
153 			break;
154 		uartputc(*uart->op++);
155 	}
156 }
157 
158 static int
liteinterrupt(ulong bit)159 liteinterrupt(ulong bit)
160 {
161 	int sts;
162 	Ctlr *ctlr;
163 	Uart *uart;
164 	Uartregs *urp;
165 
166 	uart = liteuart;
167 	if (uart == nil)
168 		return 0;
169 	ctlr = uart->regs;
170 	urp = ctlr->regs;
171 	sts = urp->status;		/* clears error bits */
172 
173 	while (urp->status & Rxfifohasdata) {
174 		uartrecv(uart, urp->rxfifo);
175 //		wakeup(&ctlr->rcvrend);
176 	}
177 	if (!(urp->status & Txfifofull)) {
178 		uartkick(uart);
179 //		wakeup(&ctlr->xmitrend);
180 	}
181 	if (sts & (Parerr|Framerr|Overrunerr|Txfifoempty|Rxfifofull|
182 	    Txfifofull|Rxfifohasdata)) {
183 		intrack(bit);
184 		return 1;
185 	}
186 	return 0;
187 }
188 
189 static void
litedisable(Uart * uart)190 litedisable(Uart* uart)
191 {
192 	Ctlr *ctlr;
193 	Uartregs *urp;
194 
195 	ctlr = uart->regs;
196 	if(ctlr->iena != 0){
197 		urp = ctlr->regs;
198 		/* wait for output to drain */
199 		while(!(urp->status & Txfifoempty))
200 			delay(1);
201 //		intrdisable(Intuart, liteinterrupt);
202 		urp->ctl = Txfiforst | Rxfiforst;
203 		barriers();
204 	}
205 }
206 
207 static void
liteenable(Uart * uart,int ie)208 liteenable(Uart* uart, int ie)
209 {
210 	int ier;
211 	Ctlr *ctlr;
212 
213 	ctlr = uart->regs;
214 
215 	/*
216  	 * Enable interrupts and turn on DTR and RTS.
217 	 * Be careful if this is called to set up a polled serial line
218 	 * early on not to try to enable interrupts as interrupt-
219 	 * -enabling mechanisms might not be set up yet.
220 	 */
221 	ier = 0;
222 	if(ie){
223 		if(ctlr->iena == 0 && !ctlr->poll){
224 			intrenable(Intuart, liteinterrupt, "uartlite");
225 			barriers();
226 			ier = Ctlintrena;
227 			ctlr->iena++;
228 		}
229 	}
230 	ctlr->regs->ctl = ier;
231 	barriers();
232 }
233 
234 static Uart*
litepnp(void)235 litepnp(void)
236 {
237 	return liteuart;
238 }
239 
240 static int
litegetc(Uart * uart)241 litegetc(Uart *uart)
242 {
243 	Ctlr *ctlr;
244 	Uartregs *urp;
245 
246 	ctlr = uart->regs;
247 	urp = ctlr->regs;
248 	while(!(urp->status & Rxfifohasdata))
249 		delay(1);
250 	return (uchar)urp->rxfifo;
251 }
252 
253 static void
liteputc(Uart * uart,int c)254 liteputc(Uart *uart, int c)
255 {
256 	Ctlr *ctlr;
257 	Uartregs *urp;
258 
259 	ctlr = uart->regs;
260 	urp = ctlr->regs;
261 	while(urp->status & Txfifofull)
262 		delay(1);
263 //		sleep(&ctlr->xmitrend, canxmit, &urp->status);
264 	urp->txfifo = (uchar)c;
265 	barriers();
266 	while(urp->status & Txfifofull)
267 		delay(1);
268 }
269 
270 /*
271  * for debugging.  no function calls are possible as this is called before
272  * we have a valid stack pointer.
273  */
274 void
uartlputc(int c)275 uartlputc(int c)
276 {
277 	ulong cnt;
278 	Uartregs *urp;
279 
280 	urp = (Uartregs *)Uartlite;
281 	for (cnt = m->cpuhz; urp->status & Txfifofull && cnt-- > 0; )
282 		;
283 	urp->txfifo = (uchar)c;
284 	barriers();
285 	for (cnt = m->cpuhz; urp->status & Txfifofull && cnt-- > 0; )
286 		;
287 }
288 
289 void
uartlputs(char * s)290 uartlputs(char *s)
291 {
292 	while (*s != '\0')
293 		uartlputc(*s++);
294 }
295 
296 static void
litepoll(Uart * uart)297 litepoll(Uart* uart)
298 {
299 	Ctlr *ctlr;
300 
301 	/*
302 	 * If PhysUart has a non-nil .poll member, this
303 	 * routine will be called from the uartclock timer.
304 	 * If the Ctlr .poll member is non-zero, when the
305 	 * Uart is enabled interrupts will not be enabled
306 	 * and the result is polled input and output.
307 	 * Not very useful here, but ports to new hardware
308 	 * or simulators can use this to get serial I/O
309 	 * without setting up the interrupt mechanism.
310 	 */
311 	ctlr = uart->regs;
312 	if(ctlr && !ctlr->iena && ctlr->poll)
313 		liteinterrupt(Intuart);
314 }
315 
316 PhysUart litephysuart = {
317 	.name		= "lite",
318 	.pnp		= litepnp,
319 	.enable		= liteenable,
320 	.disable	= litedisable,
321 	.kick		= litekick,
322 	.dobreak	= litebreak,
323 	.baud		= litebaud,
324 	.bits		= litebits,
325 	.stop		= litestop,
326 	.parity		= liteparity,
327 	.modemctl	= litemodemctl,
328 	.rts		= literts,
329 	.dtr		= litedtr,
330 	.status		= litestatus,
331 	.fifo		= litefifo,
332 	.getc		= litegetc,
333 	.putc		= liteputc,
334 //	.poll		= litepoll,
335 };
336 
337 void
uartliteconsole(void)338 uartliteconsole(void)
339 {
340 	Uart *uart;
341 
342 	uart = &liteuart[0];
343 	(*uart->phys->enable)(uart, 0);
344 	uartctl(uart, "b115200 l8 pn s1 i1 x0");
345 	uart->console = 1;
346 	consuart = uart;
347 }
348