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