xref: /plan9/sys/src/9/ppc/uartsmc.c (revision 5d9de2d38d2503efca29e12e0e32036368a7a75f)
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
baudgen(int baud)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*
smcpnp(void)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
smcsetup(Uart * uart)100 smcsetup(Uart *uart)
101 {
102 	Uartsmc *p;
103 	SMC *smc;
104 	UartData *ud;
105 
106 	ud = uart->regs;
107 
108 	/* magic addresses */
109 
110 	p = &m->immr->uartsmc[ud->smcno];
111 	smc = imm->smc + ud->smcno;	/* SMC1 */
112 	ud->smc = smc;
113 	ud->usmc = p;
114 
115 	/* step 0: disable rx/tx */
116 	smc->smcmr &= ~3;
117 
118 	ioplock();
119 
120 	/* step 1, Using Port D */
121 	if (ud->smcno != 0)
122 		panic("Don't know how to set Port D bits");
123 	imm->port[SMC1PORT].ppar |= SMRXD1|SMTXD1;
124 	imm->port[SMC1PORT].pdir |= SMTXD1;
125 	imm->port[SMC1PORT].pdir &= ~SMRXD1;
126 	imm->port[SMC1PORT].psor &= ~(SMRXD1|SMTXD1);
127 
128 	/* step 2: set up brgc1 */
129 	imm->brgc[ud->smcno]  = baudgen(uart->baud) | 0x10000;
130 
131 	/* step 3: route clock to SMC1 */
132 	imm->cmxsmr &= (ud->smcno == 0) ? ~0xb0 : ~0xb;	/* clear smcx and smcxcs */
133 
134 	iopunlock();
135 
136 	/* step 4: assign a pointer to the SMCparameter RAM */
137 	m->immr->param[ud->smcno].smcbase = (ulong)p - IMMR;
138 
139 	/* step 6: issue command to CP */
140 	if (ud->smcno == 0)
141 		cpmop(InitRxTx, SMC1ID, 0);
142 	else
143 		cpmop(InitRxTx, SMC2ID, 0);
144 
145 	/* step 7: protocol parameters */
146 	p->rfcr = 0x30;
147 	p->tfcr = 0x30;
148 }
149 
150 void
smcinit(Uart * uart)151 smcinit(Uart *uart)
152 {
153 	Uartsmc *p;
154 	SMC *smc;
155 	UartData *ud;
156 	ulong lcr;
157 	int bits;
158 
159 	ud = uart->regs;
160 
161 	if (ud->initialized)
162 		return;
163 
164 	smcsetup(uart);	/* Steps 1 through 4, PPC-dependent */
165 	p = ud->usmc;
166 	smc = ud->smc;
167 
168 	/* step 5: set up buffer descriptors */
169 	/* setup my uart structure */
170 	if (ud->rxb == nil)
171 		ud->rxb = bdalloc(1);
172 	if (ud->txb == nil)
173 		ud->txb = bdalloc(1);
174 
175 	p->rbase = ((ulong)ud->rxb) - (ulong)IMMR;
176 	p->tbase = ((ulong)ud->txb) - (ulong)IMMR;
177 
178 	/* step 8: receive buffer size */
179 	p->mrblr = Rxsize;
180 
181 	/* step 9: */
182 	p->maxidl = 15;
183 
184 	/* step 10: */
185 	p->brkln = 0;
186 	p->brkec = 0;
187 
188 	/* step 11: */
189 	p->brkcr = 0;
190 
191 	/* step 12: setup receive buffer */
192 	ud->rxb->status = BDEmpty|BDWrap|BDInt;
193 	ud->rxb->length = 0;
194 	ud->rxbuf = xspanalloc(Rxsize, 0, CACHELINESZ);
195 	ud->rxb->addr = PADDR(ud->rxbuf);
196 
197 	/* step 13: step transmit buffer */
198 	ud->txb->status = BDWrap|BDInt;
199 	ud->txb->length = 0;
200 	ud->txbuf = xspanalloc(Txsize, 0, CACHELINESZ);
201 	ud->txb->addr = PADDR(ud->txbuf);
202 
203 	/* step 14: clear events */
204 	smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
205 
206 	/*
207 	 * step 15: enable interrupts (done later)
208 	 * smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
209 	 */
210 
211 	/* step 17: set parity, no of bits, UART mode, ... */
212 	lcr = SMUart;
213 	bits = uart->bits + 1;
214 
215 	switch(uart->parity){
216 	case 'e':
217 		lcr |= (Pen|Pm);
218 		bits +=1;
219 		break;
220 	case 'o':
221 		lcr |= Pen;
222 		bits +=1;
223 		break;
224 	case 'n':
225 	default:
226 		break;
227 	}
228 
229 	if(uart->stop == 2){
230 		lcr |= Sl;
231 		bits += 1;
232 	}
233 
234 	/* Set new value and reenable if device was previously enabled */
235 	smc->smcmr = lcr |  bits <<11 | 0x3;
236 
237 	ud->initialized = 1;
238 }
239 
240 static void
smcenable(Uart * uart,int intenb)241 smcenable(Uart *uart, int intenb)
242 {
243 	UartData *ud;
244 	SMC *smc;
245 	int nr;
246 
247 	nr = uart - smcuart;
248 	if (nr < 0 || nr > Nuart)
249 		panic("No SMC %d", nr);
250 	ud = uartdata + nr;
251 	ud->smcno = nr;
252 	uart->regs = ud;
253 	if (ud->initialized == 0)
254 		smcinit(uart);
255 	if (ud->enabled || intenb == 0)
256 		return;
257 	smc = ud->smc;
258 	/* clear events */
259 	smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
260 	/* enable interrupts */
261 	smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;
262 	intrenable(VecSMC1 + ud->smcno, smcinterrupt, uart, uart->name);
263 	ud->enabled = 1;
264 }
265 
266 static long
smcstatus(Uart * uart,void * buf,long n,long offset)267 smcstatus(Uart* uart, void* buf, long n, long offset)
268 {
269 	SMC *sp;
270 	char p[128];
271 
272 	sp = ((UartData*)uart->regs)->smc;
273 	snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"
274 		"dev(%d) type(%d) framing(%d) overruns(%d)\n",
275 
276 		uart->baud,
277 		uart->hup_dcd,
278 		uart->hup_dsr,
279 		((sp->smcmr & Clen) >>11) - ((sp->smcmr&Pen) ? 1 : 0) - ((sp->smcmr&Sl) ? 2 : 1),
280 		(sp->smcmr & Pen) ? ((sp->smcmr & Pm) ? 'e': 'o'): 'n',
281 		(sp->smcmr & Sl) ? 2: 1,
282 
283 		uart->dev,
284 		uart->type,
285 		uart->ferr,
286 		uart->oerr
287 	);
288 	n = readstr(offset, buf, n, p);
289 	free(p);
290 
291 	return n;
292 }
293 
294 static void
smcfifo(Uart *,int)295 smcfifo(Uart*, int)
296 {
297 	/*
298 	 * Toggle FIFOs:
299 	 * if none, do nothing;
300 	 * reset the Rx and Tx FIFOs;
301 	 * empty the Rx buffer and clear any interrupt conditions;
302 	 * if enabling, try to turn them on.
303 	 */
304 	return;
305 }
306 
307 static void
smcdtr(Uart *,int)308 smcdtr(Uart*, int)
309 {
310 }
311 
312 static void
smcrts(Uart *,int)313 smcrts(Uart*, int)
314 {
315 }
316 
317 static void
smcmodemctl(Uart *,int)318 smcmodemctl(Uart*, int)
319 {
320 }
321 
322 static int
smcparity(Uart * uart,int parity)323 smcparity(Uart* uart, int parity)
324 {
325 	int lcr;
326 	SMC *sp;
327 
328 	sp = ((UartData*)uart->regs)->smc;
329 
330 	lcr = sp->smcmr & ~(Pen|Pm);
331 
332 	/* Disable transmitter/receiver. */
333 	sp->smcmr &= ~(Ren | Ten);
334 
335 	switch(parity){
336 	case 'e':
337 		lcr |= (Pen|Pm);
338 		break;
339 	case 'o':
340 		lcr |= Pen;
341 		break;
342 	case 'n':
343 	default:
344 		break;
345 	}
346 	/* Set new value and reenable if device was previously enabled */
347 	sp->smcmr = lcr;
348 
349 	uart->parity = parity;
350 
351 	return 0;
352 }
353 
354 static int
smcstop(Uart * uart,int stop)355 smcstop(Uart* uart, int stop)
356 {
357 	int lcr, bits;
358 	SMC *sp;
359 
360 	sp = ((UartData*)uart->regs)->smc;
361 	lcr = sp->smcmr & ~(Sl | Clen);
362 
363 	/* Disable transmitter/receiver. */
364 	sp->smcmr &= ~(Ren | Ten);
365 
366 	switch(stop){
367 	case 1:
368 		break;
369 	case 2:
370 		lcr |= Sl;
371 		break;
372 	default:
373 		return -1;
374 	}
375 
376 	bits = uart->bits + ((lcr & Pen) ? 1 : 0) + ((lcr & Sl) ? 2 : 1);
377 	lcr |= bits<<11;
378 
379 	/* Set new value and reenable if device was previously enabled */
380 	sp->smcmr = lcr;
381 
382 	uart->stop = stop;
383 
384 	return 0;
385 }
386 
387 static int
smcbits(Uart * uart,int bits)388 smcbits(Uart* uart, int bits)
389 {
390 	int lcr, b;
391 	SMC *sp;
392 
393 	if (bits < 5 || bits > 14)
394 		return -1;
395 
396 	sp = ((UartData*)uart->regs)->smc;
397 	lcr = sp->smcmr & ~Clen;
398 
399 	b = bits + ((sp->smcmr & Pen) ? 1 : 0) + ((sp->smcmr & Sl) ? 2 : 1);
400 
401 	if (b > 15)
402 		return -1;
403 
404 	/* Disable transmitter/receiver */
405 	sp->smcmr &= ~(Ren | Ten);
406 
407 	/* Set new value and reenable if device was previously enabled */
408 	sp->smcmr = lcr |  b<<11;
409 
410 	uart->bits = bits;
411 
412 	return 0;
413 }
414 
415 static int
smcbaud(Uart * uart,int baud)416 smcbaud(Uart* uart, int baud)
417 {
418 	int i;
419 	SMC *sp;
420 
421 	if (uart->enabled){
422 		sp = ((UartData*)uart->regs)->smc;
423 
424 		if(uart->freq == 0 || baud <= 0)
425 			return -1;
426 
427 		i = sp - imm->smc;
428 		imm->brgc[i] = (((m->brghz >> 4) / baud) << 1) | 0x00010000;
429 	}
430 	uart->baud = baud;
431 
432 	return 0;
433 }
434 
435 static void
smcbreak(Uart *,int)436 smcbreak(Uart*, int)
437 {
438 }
439 
440 static void
smckick(Uart * uart)441 smckick(Uart *uart)
442 {
443 	BD *txb;
444 	UartData *ud;
445 	int i;
446 
447 	if(uart->blocked)
448 		return;
449 
450 	ud = uart->regs;
451 	txb = ud->txb;
452 
453 	if (txb->status & BDReady)
454 		return;	/* Still busy */
455 
456 	for(i = 0; i < Txsize; i++){
457 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
458 			break;
459 		ud->txbuf[i] = *(uart->op++);
460 	}
461 	if (i == 0)
462 		return;
463 	dcflush(ud->txbuf, Txsize);
464 	txb->length = i;
465 	sync();
466 	txb->status |= BDReady|BDInt;
467 }
468 
469 static void
smcinterrupt(Ureg *,void * u)470 smcinterrupt(Ureg*, void* u)
471 {
472 	int i, nc;
473 	char *buf;
474 	BD *rxb;
475 	UartData *ud;
476 	Uart *uart;
477 	uchar events;
478 
479 	uart = u;
480 	if (uart == nil)
481 		panic("uart is nil");
482 	ud = uart->regs;
483 	if (ud == nil)
484 		panic("ud is nil");
485 
486 	events = ud->smc->smce;
487 	ud->smc->smce = events;	/* Clear events */
488 
489 	if (events & 0x10)
490 		iprint("smc%d: break\n", ud->smcno);
491 	if (events & 0x4)
492 		uart->oerr++;
493 	if (events & 0x1){
494 		/* Receive characters
495 		*/
496 		rxb = ud->rxb;
497 		buf = ud->rxbuf;
498 		dczap(buf, Rxsize);	/* invalidate data cache before copying */
499 		if ((rxb->status & BDEmpty) == 0){
500 			nc = rxb->length;
501 			for (i=0; i<nc; i++)
502 				uartrecv(uart, *buf++);
503 			sync();
504 			rxb->status |= BDEmpty;
505 		}else{
506 			iprint("uartsmc: unexpected receive event\n");
507 		}
508 	}
509 	if (events & 0x2){
510 		if ((ud->txb->status & BDReady) == 0)
511 			uartkick(uart);
512 	}
513 }
514 
515 static void
smcdisable(Uart * uart)516 smcdisable(Uart* uart)
517 {
518 	SMC *sp;
519 
520 	sp = ((UartData*)uart->regs)->smc;
521 	sp->smcmr &= ~(Ren | Ten);
522 }
523 
524 static int
getchars(Uart * uart,uchar * cbuf)525 getchars(Uart *uart, uchar *cbuf)
526 {
527 	int i, nc;
528 	char *buf;
529 	BD *rxb;
530 	UartData *ud;
531 
532 	ud = uart->regs;
533 	rxb = ud->rxb;
534 
535 	/* Wait for character to show up.
536 	*/
537 	buf = ud->rxbuf;
538 	while (rxb->status & BDEmpty)
539 		;
540 	nc = rxb->length;
541 	for (i=0; i<nc; i++)
542 		*cbuf++ = *buf++;
543 	sync();
544 	rxb->status |= BDEmpty;
545 
546 	return(nc);
547 }
548 
549 static int
smcgetc(Uart * uart)550 smcgetc(Uart *uart)
551 {
552 	static uchar buf[128], *p;
553 	static int cnt;
554 	char	c;
555 
556 	if (cnt <= 0) {
557 		cnt = getchars(uart, buf);
558 		p = buf;
559 	}
560 	c = *p++;
561 	cnt--;
562 
563 	return(c);
564 }
565 
566 static void
smcputc(Uart * uart,int c)567 smcputc(Uart *uart, int c)
568 {
569 	BD *txb;
570 	UartData *ud;
571 	SMC *smc;
572 
573 	ud = uart->regs;
574 	txb = ud->txb;
575 	smc = ud->smc;
576 	smc->smcm = 0;
577 
578 	/* Wait for last character to go.
579 	*/
580 	while (txb->status & BDReady)
581 		;
582 
583 	ud->txbuf[0] = c;
584 	dcflush(ud->txbuf, 1);
585 	txb->length = 1;
586 	sync();
587 	txb->status |= BDReady;
588 
589 	while (txb->status & BDReady)
590 		;
591 }
592 
593 PhysUart smcphysuart = {
594 	.name		= "smc",
595 	.pnp			= smcpnp,
596 	.enable		= smcenable,
597 	.disable		= smcdisable,
598 	.kick			= smckick,
599 	.dobreak		= smcbreak,
600 	.baud		= smcbaud,
601 	.bits			= smcbits,
602 	.stop			= smcstop,
603 	.parity		= smcparity,
604 	.modemctl	= smcmodemctl,
605 	.rts			= smcrts,
606 	.dtr			= smcdtr,
607 	.status		= smcstatus,
608 	.fifo			= smcfifo,
609 	.getc			= smcgetc,
610 	.putc			= smcputc,
611 };
612 
613 void
console(void)614 console(void)
615 {
616 	Uart *uart;
617 	int n;
618 	char *cmd, *p;
619 
620 	if((p = getconf("console")) == nil)
621 		return;
622 	n = strtoul(p, &cmd, 0);
623 	if(p == cmd)
624 		return;
625 	if(n < 0 || n >= nelem(smcuart))
626 		return;
627 	uart = smcuart + n;
628 
629 /*	uartctl(uart, "b115200 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 }
637