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