FreeBSD/Linux Kernel Cross Reference
sys/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 }
Cache object: 8e2640bf2f0f8c187ff7ecc88b1957fb
|