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