]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/mtx/uarti8250.c
ether8169: support rtl8402 variant
[plan9front.git] / sys / src / 9 / mtx / uarti8250.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 /*
10  * 8250 UART and compatibles.
11  */
12 enum {
13         Uart0           = 0x3F8,        /* COM1 */
14         Uart0IRQ        = 4,
15         Uart1           = 0x2F8,        /* COM2 */
16         Uart1IRQ        = 3,
17
18         UartFREQ        = 1843200,
19 };
20
21 enum {                                  /* I/O ports */
22         Rbr             = 0,            /* Receiver Buffer (RO) */
23         Thr             = 0,            /* Transmitter Holding (WO) */
24         Ier             = 1,            /* Interrupt Enable */
25         Iir             = 2,            /* Interrupt Identification (RO) */
26         Fcr             = 2,            /* FIFO Control (WO) */
27         Lcr             = 3,            /* Line Control */
28         Mcr             = 4,            /* Modem Control */
29         Lsr             = 5,            /* Line Status */
30         Msr             = 6,            /* Modem Status */
31         Scr             = 7,            /* Scratch Pad */
32         Dll             = 0,            /* Divisor Latch LSB */
33         Dlm             = 1,            /* Divisor Latch MSB */
34 };
35
36 enum {                                  /* Ier */
37         Erda            = 0x01,         /* Enable Received Data Available */
38         Ethre           = 0x02,         /* Enable Thr Empty */
39         Erls            = 0x04,         /* Enable Receiver Line Status */
40         Ems             = 0x08,         /* Enable Modem Status */
41 };
42
43 enum {                                  /* Iir */
44         Ims             = 0x00,         /* Ms interrupt */
45         Ip              = 0x01,         /* Interrupt Pending (not) */
46         Ithre           = 0x02,         /* Thr Empty */
47         Irda            = 0x04,         /* Received Data Available */
48         Irls            = 0x06,         /* Receiver Line Status */
49         Ictoi           = 0x0C,         /* Character Time-out Indication */
50         IirMASK         = 0x3F,
51         Ife             = 0xC0,         /* FIFOs enabled */
52 };
53
54 enum {                                  /* Fcr */
55         FIFOena         = 0x01,         /* FIFO enable */
56         FIFOrclr        = 0x02,         /* clear Rx FIFO */
57         FIFOtclr        = 0x04,         /* clear Tx FIFO */
58         FIFO1           = 0x00,         /* Rx FIFO trigger level 1 byte */
59         FIFO4           = 0x40,         /*      4 bytes */
60         FIFO8           = 0x80,         /*      8 bytes */
61         FIFO14          = 0xC0,         /*      14 bytes */
62 };
63
64 enum {                                  /* Lcr */
65         Wls5            = 0x00,         /* Word Length Select 5 bits/byte */
66         Wls6            = 0x01,         /*      6 bits/byte */
67         Wls7            = 0x02,         /*      7 bits/byte */
68         Wls8            = 0x03,         /*      8 bits/byte */
69         WlsMASK         = 0x03,
70         Stb             = 0x04,         /* 2 stop bits */
71         Pen             = 0x08,         /* Parity Enable */
72         Eps             = 0x10,         /* Even Parity Select */
73         Stp             = 0x20,         /* Stick Parity */
74         Brk             = 0x40,         /* Break */
75         Dlab            = 0x80,         /* Divisor Latch Access Bit */
76 };
77
78 enum {                                  /* Mcr */
79         Dtr             = 0x01,         /* Data Terminal Ready */
80         Rts             = 0x02,         /* Ready To Send */
81         Out1            = 0x04,         /* no longer in use */
82         Ie              = 0x08,         /* IRQ Enable */
83         Dm              = 0x10,         /* Diagnostic Mode loopback */
84 };
85
86 enum {                                  /* Lsr */
87         Dr              = 0x01,         /* Data Ready */
88         Oe              = 0x02,         /* Overrun Error */
89         Pe              = 0x04,         /* Parity Error */
90         Fe              = 0x08,         /* Framing Error */
91         Bi              = 0x10,         /* Break Interrupt */
92         Thre            = 0x20,         /* Thr Empty */
93         Temt            = 0x40,         /* Tramsmitter Empty */
94         FIFOerr         = 0x80,         /* error in receiver FIFO */
95 };
96
97 enum {                                  /* Msr */
98         Dcts            = 0x01,         /* Delta Cts */
99         Ddsr            = 0x02,         /* Delta Dsr */
100         Teri            = 0x04,         /* Trailing Edge of Ri */
101         Ddcd            = 0x08,         /* Delta Dcd */
102         Cts             = 0x10,         /* Clear To Send */
103         Dsr             = 0x20,         /* Data Set Ready */
104         Ri              = 0x40,         /* Ring Indicator */
105         Dcd             = 0x80,         /* Data Set Ready */
106 };
107
108 typedef struct Ctlr {
109         int     io;
110         int     irq;
111         int     tbdf;
112         int     iena;
113
114         uchar   sticky[8];
115
116         Lock;
117         int     fifo;
118         int     fena;
119 } Ctlr;
120
121 extern PhysUart i8250physuart;
122
123 static Ctlr i8250ctlr[2] = {
124 {       .io     = Uart0,
125         .irq    = Uart0IRQ,
126         .tbdf   = BUSUNKNOWN, },
127
128 {       .io     = Uart1,
129         .irq    = Uart1IRQ,
130         .tbdf   = BUSUNKNOWN, },
131 };
132
133 static Uart i8250uart[2] = {
134 {       .regs   = &i8250ctlr[0],
135         .name   = "COM1",
136         .freq   = UartFREQ,
137         .phys   = &i8250physuart,
138         .special=0,
139         .next   = &i8250uart[1], },
140
141 {       .regs   = &i8250ctlr[1],
142         .name   = "COM2",
143         .freq   = UartFREQ,
144         .phys   = &i8250physuart,
145         .special=0,
146         .next   = nil, },
147 };
148
149 #define csr8r(c, r)     inb((c)->io+(r))
150 #define csr8w(c, r, v)  outb((c)->io+(r), (c)->sticky[(r)]|(v))
151
152 static long
153 i8250status(Uart* uart, void* buf, long n, long offset)
154 {
155         char *p;
156         Ctlr *ctlr;
157         uchar ier, lcr, mcr, msr;
158
159         ctlr = uart->regs;
160         p = malloc(READSTR);
161         mcr = ctlr->sticky[Mcr];
162         msr = csr8r(ctlr, Msr);
163         ier = ctlr->sticky[Ier];
164         lcr = ctlr->sticky[Lcr];
165         snprint(p, READSTR,
166                 "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
167                 "dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
168
169                 uart->baud,
170                 uart->hup_dcd, 
171                 (msr & Dsr) != 0,
172                 uart->hup_dsr,
173                 (lcr & WlsMASK) + 5,
174                 (ier & Ems) != 0, 
175                 (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
176                 (mcr & Rts) != 0,
177                 (lcr & Stb) ? 2: 1,
178                 ctlr->fena,
179
180                 uart->dev,
181                 uart->type,
182                 uart->ferr,
183                 uart->oerr, 
184                 (msr & Cts) ? " cts": "",
185                 (msr & Dsr) ? " dsr": "",
186                 (msr & Dcd) ? " dcd": "",
187                 (msr & Ri) ? " ring": ""
188         );
189         n = readstr(offset, buf, n, p);
190         free(p);
191
192         return n;
193 }
194
195 static void
196 i8250fifo(Uart* uart, int on)
197 {
198         int i;
199         Ctlr *ctlr;
200
201         /*
202          * Toggle FIFOs:
203          * if none, do nothing;
204          * reset the Rx and Tx FIFOs;
205          * empty the Rx buffer and clear any interrupt conditions;
206          * if enabling, try to turn them on.
207          */
208         ctlr = uart->regs;
209
210         ilock(ctlr);
211         if(!ctlr->fifo){
212                 csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr);
213                 for(i = 0; i < 16; i++){
214                         csr8r(ctlr, Iir);
215                         csr8r(ctlr, Rbr);
216                 }
217   
218                 ctlr->fena = 0;
219                 if(on){
220                         csr8w(ctlr, Fcr, FIFO4|FIFOena);
221                         if(!(csr8r(ctlr, Iir) & Ife))
222                                 ctlr->fifo = 1;
223                         ctlr->fena = 1;
224                 }
225         }
226         iunlock(ctlr);
227 }
228
229 static void
230 i8250dtr(Uart* uart, int on)
231 {
232         Ctlr *ctlr;
233
234         /*
235          * Toggle DTR.
236          */
237         ctlr = uart->regs;
238         if(on)
239                 ctlr->sticky[Mcr] |= Dtr;
240         else
241                 ctlr->sticky[Mcr] &= ~Dtr;
242         csr8w(ctlr, Mcr, 0);
243 }
244
245 static void
246 i8250rts(Uart* uart, int on)
247 {
248         Ctlr *ctlr;
249
250         /*
251          * Toggle RTS.
252          */
253         ctlr = uart->regs;
254         if(on)
255                 ctlr->sticky[Mcr] |= Rts;
256         else
257                 ctlr->sticky[Mcr] &= ~Rts;
258         csr8w(ctlr, Mcr, 0);
259 }
260
261 static void
262 i8250modemctl(Uart* uart, int on)
263 {
264         Ctlr *ctlr;
265
266         ctlr = uart->regs;
267         ilock(&uart->tlock);
268         if(on){
269                 ctlr->sticky[Ier] |= Ems;
270                 csr8w(ctlr, Ier, 0);
271                 uart->modem = 1;
272                 uart->cts = csr8r(ctlr, Msr) & Cts;
273         }
274         else{
275                 ctlr->sticky[Ier] &= ~Ems;
276                 csr8w(ctlr, Ier, 0);
277                 uart->modem = 0;
278                 uart->cts = 1;
279         }
280         iunlock(&uart->tlock);
281
282         /* modem needs fifo */
283         (*uart->phys->fifo)(uart, on);
284 }
285
286 static int
287 i8250parity(Uart* uart, int parity)
288 {
289         int lcr;
290         Ctlr *ctlr;
291
292         ctlr = uart->regs;
293         lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
294
295         switch(parity){
296         case 'e':
297                 lcr |= Eps|Pen;
298                 break;
299         case 'o':
300                 lcr |= Pen;
301                 break;
302         case 'n':
303         default:
304                 break;
305         }
306         ctlr->sticky[Lcr] = lcr;
307         csr8w(ctlr, Lcr, 0);
308
309         uart->parity = parity;
310
311         return 0;
312 }
313
314 static int
315 i8250stop(Uart* uart, int stop)
316 {
317         int lcr;
318         Ctlr *ctlr;
319
320         ctlr = uart->regs;
321         lcr = ctlr->sticky[Lcr] & ~Stb;
322
323         switch(stop){
324         case 1:
325                 break;
326         case 2:
327                 lcr |= Stb;
328                 break;
329         default:
330                 return -1;
331         }
332         ctlr->sticky[Lcr] = lcr;
333         csr8w(ctlr, Lcr, 0);
334
335         uart->stop = stop;
336
337         return 0;
338 }
339
340 static int
341 i8250bits(Uart* uart, int bits)
342 {
343         int lcr;
344         Ctlr *ctlr;
345
346         ctlr = uart->regs;
347         lcr = ctlr->sticky[Lcr] & ~WlsMASK;
348
349         switch(bits){
350         case 5:
351                 lcr |= Wls5;
352                 break;
353         case 6:
354                 lcr |= Wls6;
355                 break;
356         case 7:
357                 lcr |= Wls7;
358                 break;
359         case 8:
360                 lcr |= Wls8;
361                 break;
362         default:
363                 return -1;
364         }
365         ctlr->sticky[Lcr] = lcr;
366         csr8w(ctlr, Lcr, 0);
367
368         uart->bits = bits;
369
370         return 0;
371 }
372
373 static int
374 i8250baud(Uart* uart, int baud)
375 {
376         ulong bgc;
377         Ctlr *ctlr;
378
379         /*
380          * Set the Baud rate by calculating and setting the Baud rate
381          * Generator Constant. This will work with fairly non-standard
382          * Baud rates.
383          */
384         if(uart->freq == 0 || baud <= 0)
385                 return -1;
386         bgc = (uart->freq+8*baud-1)/(16*baud);
387
388         ctlr = uart->regs;
389         csr8w(ctlr, Lcr, Dlab);
390         outb(ctlr->io+Dlm, bgc>>8);
391         outb(ctlr->io+Dll, bgc);
392         csr8w(ctlr, Lcr, 0);
393
394         uart->baud = baud;
395
396         return 0;
397 }
398
399 static void
400 i8250break(Uart* uart, int ms)
401 {
402         Ctlr *ctlr;
403
404         /*
405          * Send a break.
406          */
407         if(ms == 0)
408                 ms = 200;
409
410         ctlr = uart->regs;
411         csr8w(ctlr, Lcr, Brk);
412         tsleep(&up->sleep, return0, 0, ms);
413         csr8w(ctlr, Lcr, 0);
414 }
415
416 static void
417 i8250kick(Uart* uart)
418 {
419         int i;
420         Ctlr *ctlr;
421
422         if(uart->cts == 0 || uart->blocked)
423                 return;
424
425         /*
426          *  128 here is an arbitrary limit to make sure
427          *  we don't stay in this loop too long.  If the
428          *  chip's output queue is longer than 128, too
429          *  bad -- presotto
430          */
431         ctlr = uart->regs;
432         for(i = 0; i < 128; i++){
433                 if(!(csr8r(ctlr, Lsr) & Thre))
434                         break;
435                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
436                         break;
437                 outb(ctlr->io+Thr, *(uart->op++));
438         }
439 }
440
441 static void
442 i8250interrupt(Ureg*, void* arg)
443 {
444         Ctlr *ctlr;
445         Uart *uart;
446         int iir, lsr, old, r;
447
448         uart = arg;
449
450         ctlr = uart->regs;
451         for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
452                 switch(iir & IirMASK){
453                 case Ims:               /* Ms interrupt */
454                         r = csr8r(ctlr, Msr);
455                         if(r & Dcts){
456                                 ilock(&uart->tlock);
457                                 old = uart->cts;
458                                 uart->cts = r & Cts;
459                                 if(old == 0 && uart->cts)
460                                         uart->ctsbackoff = 2;
461                                 iunlock(&uart->tlock);
462                         }
463                         if(r & Ddsr){
464                                 old = r & Dsr;
465                                 if(uart->hup_dsr && uart->dsr && !old)
466                                         uart->dohup = 1;
467                                 uart->dsr = old;
468                         }
469                         if(r & Ddcd){
470                                 old = r & Dcd;
471                                 if(uart->hup_dcd && uart->dcd && !old)
472                                         uart->dohup = 1;
473                                 uart->dcd = old;
474                         }
475                         break;
476                 case Ithre:             /* Thr Empty */
477                         uartkick(uart);
478                         break;
479                 case Irda:              /* Received Data Available */
480                 case Ictoi:             /* Character Time-out Indication */
481                         /*
482                          * Consume any received data.
483                          * If the received byte came in with a break,
484                          * parity or framing error, throw it away;
485                          * overrun is an indication that something has
486                          * already been tossed.
487                          */
488                         while((lsr = csr8r(ctlr, Lsr)) & Dr){
489                                 if(lsr & Oe)
490                                         uart->oerr++;
491                                 if(lsr & Pe)
492                                         uart->perr++;
493                                 if(lsr & Fe)
494                                         uart->ferr++;
495                                 r = csr8r(ctlr, Rbr);
496                                 if(!(lsr & (Bi|Fe|Pe)))
497                                         uartrecv(uart, r);
498                         }
499                         break;
500                 default:
501                         iprint("weird uart interrupt 0x%2.2uX\n", iir);
502                         break;
503                 }
504         }
505 }
506
507 static void
508 i8250disable(Uart* uart)
509 {
510         Ctlr *ctlr;
511
512         /*
513          * Turn off DTR and RTS, disable interrupts and fifos.
514          */
515         (*uart->phys->dtr)(uart, 0);
516         (*uart->phys->rts)(uart, 0);
517         (*uart->phys->fifo)(uart, 0);
518
519         ctlr = uart->regs;
520         ctlr->sticky[Ier] = 0;
521         csr8w(ctlr, Ier, 0);
522 }
523
524 static void
525 i8250enable(Uart* uart, int ie)
526 {
527         Ctlr *ctlr;
528
529         /*
530          * Enable interrupts and turn on DTR and RTS.
531          * Be careful if this is called to set up a polled serial line
532          * early on not to try to enable interrupts as interrupt-
533          * -enabling mechanisms might not be set up yet.
534          */
535         ctlr = uart->regs;
536         if(ie){
537                 if(ctlr->iena == 0){
538                         intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
539                         ctlr->iena = 1;
540                 }
541                 ctlr->sticky[Ier] = Ethre|Erda;
542                 ctlr->sticky[Mcr] |= Ie;
543         }
544         else{
545                 ctlr->sticky[Ier] = 0;
546                 ctlr->sticky[Mcr] = 0;
547         }
548         csr8w(ctlr, Ier, ctlr->sticky[Ier]);
549         csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
550
551         (*uart->phys->dtr)(uart, 1);
552         (*uart->phys->rts)(uart, 1);
553 }
554
555 static Uart*
556 i8250pnp(void)
557 {
558         return i8250uart;
559 }
560
561 static int
562 i8250getc(Uart *uart)
563 {
564         Ctlr *ctlr;
565
566         ctlr = uart->regs;
567         while(!(csr8r(ctlr, Lsr)&Dr))
568                 delay(1);
569         return csr8r(ctlr, Rbr);
570 }
571
572 static void
573 i8250putc(Uart *uart, int c)
574 {
575         int i;
576         Ctlr *ctlr;
577
578         ctlr = uart->regs;
579         for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
580                 delay(1);
581         outb(ctlr->io+Thr, c);
582         for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
583                 delay(1);
584 }
585
586 PhysUart i8250physuart = {
587         .name           = "i8250",
588         .pnp            = i8250pnp,
589         .enable         = i8250enable,
590         .disable        = i8250disable,
591         .kick           = i8250kick,
592         .dobreak        = i8250break,
593         .baud           = i8250baud,
594         .bits           = i8250bits,
595         .stop           = i8250stop,
596         .parity         = i8250parity,
597         .modemctl       = i8250modemctl,
598         .rts            = i8250rts,
599         .dtr            = i8250dtr,
600         .status         = i8250status,
601         .fifo           = i8250fifo,
602         .getc           = i8250getc,
603         .putc           = i8250putc,
604 };
605
606 void
607 i8250console(void)
608 {
609         Uart *uart;
610         int n;
611         char *cmd, *p;
612
613         if((p = getconf("console")) == nil)
614                 return;
615         n = strtoul(p, &cmd, 0);
616         if(p == cmd)
617                 return;
618         switch(n){
619         default:
620                 return;
621         case 0:
622                 uart = &i8250uart[0];
623                 break;
624         case 1:
625                 uart = &i8250uart[1];
626                 break;  
627         }
628
629         uartctl(uart, "b9600 l8 pn s1");
630         if(*cmd != '\0')
631                 uartctl(uart, cmd);
632         (*uart->phys->enable)(uart, 0);
633
634         consuart = uart;
635         uart->console = 1;
636