]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/uartsmc.c
ether82563: add 0x15bd i219-lm variant (thanks crab1)
[plan9front.git] / sys / src / 9 / ppc / uartsmc.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 "imm.h"
8 #include "../port/error.h"
9 #include "../ppc/uartsmc.h"
10
11 /*
12  * PowerPC 8260 SMC UART
13  */
14
15 enum {
16         /* SMC Mode Registers */
17         Clen            = 0x7800,       /* Character length */
18         Sl              = 0x0400,       /* Stop length, 0: one stop bit, 1: two */
19         Pen             = 0x0200,       /* Parity enable */
20         Pm              = 0x0100,       /* Parity mode, 0 is odd */
21         Sm              = 0x0030,       /* SMC mode, two bits */
22         SMUart  = 0x0020,       /* SMC mode, 0b10 is uart */
23         Dm              = 0x000c,       /* Diagnostic mode, 00 is normal */
24         Ten             = 0x0002,       /* Transmit enable, 1 is enabled */
25         Ren             = 0x0001,       /* Receive enable, 1 is enabled */
26
27         /* SMC Event/Mask Registers */
28         ce_Brke = 0x0040,       /* Break end */
29         ce_Br   = 0x0020,       /* Break character received */
30         ce_Bsy  = 0x0004,       /* Busy condition */
31         ce_Txb  = 0x0002,       /* Tx buffer */
32         ce_Rxb  = 0x0001,       /* Rx buffer */
33
34         /* Receive/Transmit Buffer Descriptor Control bits */
35         BDContin=       1<<9,
36         BDIdle=         1<<8,
37         BDPreamble=     1<<8,
38         BDBreak=        1<<5,
39         BDFrame=        1<<4,
40         BDParity=       1<<3,
41         BDOverrun=      1<<1,
42
43         /* Tx and Rx buffer sizes (32 bytes) */
44         Rxsize=         CACHELINESZ,
45         Txsize=         CACHELINESZ,
46 };
47
48 extern PhysUart smcphysuart;
49
50 Uart smcuart[Nuart] = {
51         {
52                 .name = "SMC1",
53                 .baud = 115200,
54                 .bits = 8,
55                 .stop = 1,
56                 .parity = 'n',
57                 .phys = &smcphysuart,
58                 .special = 0,
59         },
60 /*      Only configure SMC1 for now
61         {
62                 .name = "SMC2",
63                 .baud = 115200,
64                 .bits = 8,
65                 .stop = 1,
66                 .parity = 'n',
67                 .phys = &smcphysuart,
68                 .special = 0,
69         },
70 */
71 };
72
73 int uartinited = 0;
74
75 static void smcinterrupt(Ureg*, void*);
76 static void smcputc(Uart *uart, int c);
77
78 int
79 baudgen(int baud)
80 {
81         int d;
82
83         d = ((m->brghz+(baud>>1))/baud)>>4;
84         if(d >= (1<<12))
85                 return ((d+15)>>3)|1;
86         return d<<1;
87 }
88
89 static Uart*
90 smcpnp(void)
91 {
92         int i;
93
94         for (i = 0; i < nelem(smcuart) - 1; i++)
95                 smcuart[i].next = smcuart + i + 1;
96         return smcuart;
97 }
98
99 void
100 smcinit(Uart *uart)
101 {
102         Uartsmc *p;
103         SMC *smc;
104         UartData *ud;
105         ulong lcr;
106         int bits;
107
108         ud = uart->regs;
109
110         if (ud->initialized)
111                 return;
112
113         smcsetup(uart); /* Steps 1 through 4, PPC-dependent */
114         p = ud->usmc;
115         smc = ud->smc;
116
117         /* step 5: set up buffer descriptors */
118         /* setup my uart structure */
119         if (ud->rxb == nil)
120                 ud->rxb = bdalloc(1);
121         if (ud->txb == nil)
122                 ud->txb = bdalloc(1);
123
124         p->rbase = ((ulong)ud->rxb) - (ulong)IMMR;
125         p->tbase = ((ulong)ud->txb) - (ulong)IMMR;
126
127         /* step 8: receive buffer size */
128         p->mrblr = Rxsize;
129
130         /* step 9: */
131         p->maxidl = 15;
132
133         /* step 10: */
134         p->brkln = 0;
135         p->brkec = 0;
136
137         /* step 11: */
138         p->brkcr = 0;
139
140         /* step 12: setup receive buffer */
141         ud->rxb->status = BDEmpty|BDWrap|BDInt;
142         ud->rxb->length = 0;
143         ud->rxbuf = xspanalloc(Rxsize, 0, CACHELINESZ);
144         ud->rxb->addr = PADDR(ud->rxbuf);
145
146         /* step 13: step transmit buffer */
147         ud->txb->status = BDWrap|BDInt;
148         ud->txb->length = 0;
149         ud->txbuf = xspanalloc(Txsize, 0, CACHELINESZ);
150         ud->txb->addr = PADDR(ud->txbuf);
151
152         /* step 14: clear events */
153         smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
154
155         /* 
156          * step 15: enable interrupts (done later)
157          * smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
158          */
159
160         /* step 17: set parity, no of bits, UART mode, ... */
161         lcr = SMUart;
162         bits = uart->bits + 1;
163
164         switch(uart->parity){
165         case 'e':
166                 lcr |= (Pen|Pm);
167                 bits +=1;
168                 break;
169         case 'o':
170                 lcr |= Pen;
171                 bits +=1;
172                 break;
173         case 'n':
174         default:
175                 break;
176         }
177
178         if(uart->stop == 2){
179                 lcr |= Sl;
180                 bits += 1;
181         }
182
183         /* Set new value and reenable if device was previously enabled */
184         smc->smcmr = lcr |  bits <<11 | 0x3;
185
186         ud->initialized = 1;
187 }
188
189 static void
190 smcenable(Uart *uart, int intenb)
191 {
192         UartData *ud;
193         SMC *smc;
194         int nr;
195
196         nr = uart - smcuart;
197         if (nr < 0 || nr > Nuart)
198                 panic("No SMC %d", nr);
199         ud = uartdata + nr;
200         ud->smcno = nr;
201         uart->regs = ud;
202         if (ud->initialized == 0)
203                 smcinit(uart);
204         if (ud->enabled || intenb == 0)
205                 return;
206         smc = ud->smc;
207         /* clear events */
208         smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
209         /* enable interrupts */
210         smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
211         intrenable(VecSMC1 + ud->smcno, smcinterrupt, uart, uart->name);
212         ud->enabled = 1;
213 }
214
215 static long
216 smcstatus(Uart* uart, void* buf, long n, long offset)
217 {
218         SMC *sp;
219         char p[128];
220
221         sp = ((UartData*)uart->regs)->smc;
222         snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
223                 "dev(%d) type(%d) framing(%d) overruns(%d)\n",
224
225                 uart->baud,
226                 uart->hup_dcd, 
227                 uart->hup_dsr,
228                 ((sp->smcmr & Clen) >>11) - ((sp->smcmr&Pen) ? 1 : 0) - ((sp->smcmr&Sl) ? 2 : 1),
229                 (sp->smcmr & Pen) ? ((sp->smcmr & Pm) ? 'e': 'o'): 'n',
230                 (sp->smcmr & Sl) ? 2: 1,
231
232                 uart->dev,
233                 uart->type,
234                 uart->ferr,
235                 uart->oerr 
236         );
237         n = readstr(offset, buf, n, p);
238         free(p);
239
240         return n;
241 }
242
243 static void
244 smcfifo(Uart*, int)
245 {
246         /*
247          * Toggle FIFOs:
248          * if none, do nothing;
249          * reset the Rx and Tx FIFOs;
250          * empty the Rx buffer and clear any interrupt conditions;
251          * if enabling, try to turn them on.
252          */
253         return;
254 }
255
256 static void
257 smcdtr(Uart*, int)
258 {
259 }
260
261 static void
262 smcrts(Uart*, int)
263 {
264 }
265
266 static void
267 smcmodemctl(Uart*, int)
268 {
269 }
270
271 static int
272 smcparity(Uart* uart, int parity)
273 {
274         int lcr;
275         SMC *sp;
276
277         sp = ((UartData*)uart->regs)->smc;
278
279         lcr = sp->smcmr & ~(Pen|Pm);
280
281         /* Disable transmitter/receiver. */
282         sp->smcmr &= ~(Ren | Ten);
283
284         switch(parity){
285         case 'e':
286                 lcr |= (Pen|Pm);
287                 break;
288         case 'o':
289                 lcr |= Pen;
290                 break;
291         case 'n':
292         default:
293                 break;
294         }
295         /* Set new value and reenable if device was previously enabled */
296         sp->smcmr = lcr;
297
298         uart->parity = parity;
299
300         return 0;
301 }
302
303 static int
304 smcstop(Uart* uart, int stop)
305 {
306         int lcr, bits;
307         SMC *sp;
308
309         sp = ((UartData*)uart->regs)->smc;
310         lcr = sp->smcmr & ~(Sl | Clen);
311
312         /* Disable transmitter/receiver. */
313         sp->smcmr &= ~(Ren | Ten);
314
315         switch(stop){
316         case 1:
317                 break;
318         case 2:
319                 lcr |= Sl;
320                 break;
321         default:
322                 return -1;
323         }
324
325         bits = uart->bits + ((lcr & Pen) ? 1 : 0) + ((lcr & Sl) ? 2 : 1);
326         lcr |= bits<<11;
327
328         /* Set new value and reenable if device was previously enabled */
329         sp->smcmr = lcr;
330
331         uart->stop = stop;
332
333         return 0;
334 }
335
336 static int
337 smcbits(Uart* uart, int bits)
338 {
339         int lcr, b;
340         SMC *sp;
341
342         if (bits < 5 || bits > 14)
343                 return -1;
344
345         sp = ((UartData*)uart->regs)->smc;
346         lcr = sp->smcmr & ~Clen;
347
348         b = bits + ((sp->smcmr & Pen) ? 1 : 0) + ((sp->smcmr & Sl) ? 2 : 1);
349
350         if (b > 15)
351                 return -1;
352
353         /* Disable transmitter/receiver */
354         sp->smcmr &= ~(Ren | Ten);
355
356         /* Set new value and reenable if device was previously enabled */
357         sp->smcmr = lcr |  b<<11;
358
359         uart->bits = bits;
360
361         return 0;
362 }
363
364 static int
365 smcbaud(Uart* uart, int baud)
366 {
367         int i;
368         SMC *sp;
369
370         if (uart->enabled){
371                 sp = ((UartData*)uart->regs)->smc;
372         
373                 if(uart->freq == 0 || baud <= 0)
374                         return -1;
375         
376                 i = sp - imm->smc;
377                 imm->brgc[i] = (((m->brghz >> 4) / baud) << 1) | 0x00010000;
378         }
379         uart->baud = baud;
380
381         return 0;
382 }
383
384 static void
385 smcbreak(Uart*, int)
386 {
387 }
388
389 static void
390 smckick(Uart *uart)
391 {
392         BD *txb;
393         UartData *ud;
394         int i;
395
396         if(uart->blocked)
397                 return;
398
399         ud = uart->regs;
400         txb = ud->txb;
401
402         if (txb->status & BDReady)
403                 return; /* Still busy */
404
405         for(i = 0; i < Txsize; i++){
406                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
407                         break;
408                 ud->txbuf[i] = *(uart->op++);
409         }
410         if (i == 0)
411                 return;
412         dcflush(ud->txbuf, Txsize);
413         txb->length = i;
414         sync();
415         txb->status |= BDReady|BDInt;
416 }
417
418 static void
419 smcinterrupt(Ureg*, void* u)
420 {
421         int i, nc;
422         char *buf;
423         BD *rxb;
424         UartData *ud;
425         Uart *uart;
426         uchar events;
427
428         uart = u;
429         if (uart == nil)
430                 panic("uart is nil");
431         ud = uart->regs;
432         if (ud == nil)
433                 panic("ud is nil");
434
435         events = ud->smc->smce;
436         ud->smc->smce = events; /* Clear events */
437
438         if (events & 0x10)
439                 iprint("smc%d: break\n", ud->smcno);
440         if (events & 0x4)
441                 uart->oerr++;
442         if (events & 0x1){
443                 /* Receive characters
444                 */
445                 rxb = ud->rxb;
446                 buf = ud->rxbuf;
447                 dczap(buf, Rxsize);     /* invalidate data cache before copying */
448                 if ((rxb->status & BDEmpty) == 0){
449                         nc = rxb->length;
450                         for (i=0; i<nc; i++)
451                                 uartrecv(uart, *buf++);
452                         sync();
453                         rxb->status |= BDEmpty;
454                 }else{
455                         iprint("uartsmc: unexpected receive event\n");
456                 }
457         }
458         if (events & 0x2){
459                 if ((ud->txb->status & BDReady) == 0)
460                         uartkick(uart);
461         }
462 }
463
464 static void
465 smcdisable(Uart* uart)
466 {
467         SMC *sp;
468
469         sp = ((UartData*)uart->regs)->smc;
470         sp->smcmr &= ~(Ren | Ten);
471 }
472
473 static int
474 getchars(Uart *uart, uchar *cbuf)
475 {
476         int i, nc;
477         char *buf;
478         BD *rxb;
479         UartData *ud;
480
481         ud = uart->regs;
482         rxb = ud->rxb;
483
484         /* Wait for character to show up.
485         */
486         buf = ud->rxbuf;
487         while (rxb->status & BDEmpty)
488                 ;
489         nc = rxb->length;
490         for (i=0; i<nc; i++)
491                 *cbuf++ = *buf++;
492         sync();
493         rxb->status |= BDEmpty;
494
495         return(nc);
496 }
497
498 static int
499 smcgetc(Uart *uart)
500 {
501         static uchar buf[128], *p;
502         static int cnt;
503         char    c;
504
505         if (cnt <= 0) {
506                 cnt = getchars(uart, buf);
507                 p = buf;
508         }
509         c = *p++;
510         cnt--;
511
512         return(c);
513 }
514
515 static void
516 smcputc(Uart *uart, int c)
517 {
518         BD *txb;
519         UartData *ud;
520         SMC *smc;
521
522         ud = uart->regs;
523         txb = ud->txb;
524         smc = ud->smc;
525         smc->smcm = 0;
526
527         /* Wait for last character to go.
528         */
529         while (txb->status & BDReady)
530                 ;
531
532         ud->txbuf[0] = c;
533         dcflush(ud->txbuf, 1);
534         txb->length = 1;
535         sync();
536         txb->status |= BDReady;
537
538         while (txb->status & BDReady)
539                 ;
540 }
541
542 PhysUart smcphysuart = {
543         .name           = "smc",
544         .pnp                    = smcpnp,
545         .enable         = smcenable,
546         .disable                = smcdisable,
547         .kick                   = smckick,
548         .dobreak                = smcbreak,
549         .baud           = smcbaud,
550         .bits                   = smcbits,
551         .stop                   = smcstop,
552         .parity         = smcparity,
553         .modemctl       = smcmodemctl,
554         .rts                    = smcrts,
555         .dtr                    = smcdtr,
556         .status         = smcstatus,
557         .fifo                   = smcfifo,
558         .getc                   = smcgetc,
559         .putc                   = smcputc,
560 };
561
562 void
563 console(void)
564 {
565         Uart *uart;
566         int n;
567         char *cmd, *p;
568
569         if((p = getconf("console")) == nil)
570                 return;
571         n = strtoul(p, &cmd, 0);
572         if(p == cmd)
573                 return;
574         if(n < 0 || n >= nelem(smcuart))
575                 return;
576         uart = smcuart + n;
577
578 /*      uartctl(uart, "b115200 l8 pn s1"); */
579         if(*cmd != '\0')
580                 uartctl(uart, cmd);
581         (*uart->phys->enable)(uart, 0);
582
583         consuart = uart;
584         uart->console = 1;
585