645 lines · 11.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "imm.h"#include "../port/error.h"#include "../ppc/uartsmc.h" /* * PowerPC 8260 SMC UART */ enum {	/* SMC Mode Registers */	Clen		= 0x7800,	/* Character length */	Sl		= 0x0400,	/* Stop length, 0: one stop bit, 1: two */	Pen		= 0x0200,	/* Parity enable */	Pm		= 0x0100,	/* Parity mode, 0 is odd */	Sm		= 0x0030,	/* SMC mode, two bits */	SMUart	= 0x0020,	/* SMC mode, 0b10 is uart */	Dm		= 0x000c,	/* Diagnostic mode, 00 is normal */	Ten		= 0x0002,	/* Transmit enable, 1 is enabled */	Ren		= 0x0001,	/* Receive enable, 1 is enabled */ 	/* SMC Event/Mask Registers */	ce_Brke	= 0x0040,	/* Break end */	ce_Br	= 0x0020,	/* Break character received */	ce_Bsy	= 0x0004,	/* Busy condition */	ce_Txb	= 0x0002,	/* Tx buffer */	ce_Rxb	= 0x0001,	/* Rx buffer */ 	/* Receive/Transmit Buffer Descriptor Control bits */	BDContin=	1<<9,	BDIdle=		1<<8,	BDPreamble=	1<<8,	BDBreak=	1<<5,	BDFrame=	1<<4,	BDParity=	1<<3,	BDOverrun=	1<<1, 	/* Tx and Rx buffer sizes (32 bytes) */	Rxsize=		CACHELINESZ,	Txsize=		CACHELINESZ,}; extern PhysUart smcphysuart; Uart smcuart[Nuart] = {	{		.name = "SMC1",		.baud = 115200,		.bits = 8,		.stop = 1,		.parity = 'n',		.phys = &smcphysuart,		.special = 0,	},/*	Only configure SMC1 for now	{		.name = "SMC2",		.baud = 115200,		.bits = 8,		.stop = 1,		.parity = 'n',		.phys = &smcphysuart,		.special = 0,	},*/}; int uartinited = 0; static void smcinterrupt(Ureg*, void*);static void smcputc(Uart *uart, int c); intbaudgen(int baud){	int d; 	d = ((m->brghz+(baud>>1))/baud)>>4;	if(d >= (1<<12))		return ((d+15)>>3)|1;	return d<<1;} static Uart*smcpnp(void){	int i; 	for (i = 0; i < nelem(smcuart) - 1; i++)		smcuart[i].next = smcuart + i + 1;	return smcuart;} voidsmcsetup(Uart *uart){	Uartsmc *p;	SMC *smc;	UartData *ud; 	ud = uart->regs; 	/* magic addresses */ 	p = &m->immr->uartsmc[ud->smcno];	smc = imm->smc + ud->smcno;	/* SMC1 */	ud->smc = smc;	ud->usmc = p; 	/* step 0: disable rx/tx */	smc->smcmr &= ~3; 	ioplock(); 	/* step 1, Using Port D */	if (ud->smcno != 0)		panic("Don't know how to set Port D bits");	imm->port[SMC1PORT].ppar |= SMRXD1|SMTXD1;	imm->port[SMC1PORT].pdir |= SMTXD1;	imm->port[SMC1PORT].pdir &= ~SMRXD1;	imm->port[SMC1PORT].psor &= ~(SMRXD1|SMTXD1); 	/* step 2: set up brgc1 */	imm->brgc[ud->smcno]  = baudgen(uart->baud) | 0x10000; 	/* step 3: route clock to SMC1 */	imm->cmxsmr &= (ud->smcno == 0) ? ~0xb0 : ~0xb;	/* clear smcx and smcxcs */ 	iopunlock(); 	/* step 4: assign a pointer to the SMCparameter RAM */	m->immr->param[ud->smcno].smcbase = (ulong)p - IMMR; 	/* step 6: issue command to CP */	if (ud->smcno == 0)		cpmop(InitRxTx, SMC1ID, 0);	else		cpmop(InitRxTx, SMC2ID, 0); 	/* step 7: protocol parameters */	p->rfcr = 0x30;	p->tfcr = 0x30;} voidsmcinit(Uart *uart){	Uartsmc *p;	SMC *smc;	UartData *ud;	ulong lcr;	int bits; 	ud = uart->regs; 	if (ud->initialized)		return; 	smcsetup(uart);	/* Steps 1 through 4, PPC-dependent */	p = ud->usmc;	smc = ud->smc; 	/* step 5: set up buffer descriptors */	/* setup my uart structure */	if (ud->rxb == nil)		ud->rxb = bdalloc(1);	if (ud->txb == nil)		ud->txb = bdalloc(1); 	p->rbase = ((ulong)ud->rxb) - (ulong)IMMR;	p->tbase = ((ulong)ud->txb) - (ulong)IMMR; 	/* step 8: receive buffer size */	p->mrblr = Rxsize; 	/* step 9: */	p->maxidl = 15; 	/* step 10: */	p->brkln = 0;	p->brkec = 0; 	/* step 11: */	p->brkcr = 0; 	/* step 12: setup receive buffer */	ud->rxb->status = BDEmpty|BDWrap|BDInt;	ud->rxb->length = 0;	ud->rxbuf = xspanalloc(Rxsize, 0, CACHELINESZ);	ud->rxb->addr = PADDR(ud->rxbuf); 	/* step 13: step transmit buffer */	ud->txb->status = BDWrap|BDInt;	ud->txb->length = 0;	ud->txbuf = xspanalloc(Txsize, 0, CACHELINESZ);	ud->txb->addr = PADDR(ud->txbuf); 	/* step 14: clear events */	smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb; 	/* 	 * step 15: enable interrupts (done later)	 * smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;	 */ 	/* step 17: set parity, no of bits, UART mode, ... */	lcr = SMUart;	bits = uart->bits + 1; 	switch(uart->parity){	case 'e':		lcr |= (Pen|Pm);		bits +=1;		break;	case 'o':		lcr |= Pen;		bits +=1;		break;	case 'n':	default:		break;	} 	if(uart->stop == 2){		lcr |= Sl;		bits += 1;	} 	/* Set new value and reenable if device was previously enabled */	smc->smcmr = lcr |  bits <<11 | 0x3; 	ud->initialized = 1;} static voidsmcenable(Uart *uart, int intenb){	UartData *ud;	SMC *smc;	int nr; 	nr = uart - smcuart;	if (nr < 0 || nr > Nuart)		panic("No SMC %d", nr);	ud = uartdata + nr;	ud->smcno = nr;	uart->regs = ud;	if (ud->initialized == 0)		smcinit(uart);	if (ud->enabled || intenb == 0)		return;	smc = ud->smc;	/* clear events */	smc->smce = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;	/* enable interrupts */	smc->smcm = ce_Brke | ce_Br | ce_Bsy | ce_Txb | ce_Rxb;	intrenable(VecSMC1 + ud->smcno, smcinterrupt, uart, uart->name);	ud->enabled = 1;} static longsmcstatus(Uart* uart, void* buf, long n, long offset){	SMC *sp;	char p[128]; 	sp = ((UartData*)uart->regs)->smc;	snprint(p, sizeof p, "b%d c%d e%d l%d m0 p%c s%d i1\n"		"dev(%d) type(%d) framing(%d) overruns(%d)\n", 		uart->baud,		uart->hup_dcd, 		uart->hup_dsr,		((sp->smcmr & Clen) >>11) - ((sp->smcmr&Pen) ? 1 : 0) - ((sp->smcmr&Sl) ? 2 : 1),		(sp->smcmr & Pen) ? ((sp->smcmr & Pm) ? 'e': 'o'): 'n',		(sp->smcmr & Sl) ? 2: 1, 		uart->dev,		uart->type,		uart->ferr,		uart->oerr 	);	n = readstr(offset, buf, n, p);	free(p); 	return n;} static voidsmcfifo(Uart*, int){	/*	 * Toggle FIFOs:	 * if none, do nothing;	 * reset the Rx and Tx FIFOs;	 * empty the Rx buffer and clear any interrupt conditions;	 * if enabling, try to turn them on.	 */	return;} static voidsmcdtr(Uart*, int){} static voidsmcrts(Uart*, int){} static voidsmcmodemctl(Uart*, int){} static intsmcparity(Uart* uart, int parity){	int lcr;	SMC *sp; 	sp = ((UartData*)uart->regs)->smc; 	lcr = sp->smcmr & ~(Pen|Pm); 	/* Disable transmitter/receiver. */	sp->smcmr &= ~(Ren | Ten); 	switch(parity){	case 'e':		lcr |= (Pen|Pm);		break;	case 'o':		lcr |= Pen;		break;	case 'n':	default:		break;	}	/* Set new value and reenable if device was previously enabled */	sp->smcmr = lcr; 	uart->parity = parity; 	return 0;} static intsmcstop(Uart* uart, int stop){	int lcr, bits;	SMC *sp; 	sp = ((UartData*)uart->regs)->smc;	lcr = sp->smcmr & ~(Sl | Clen); 	/* Disable transmitter/receiver. */	sp->smcmr &= ~(Ren | Ten); 	switch(stop){	case 1:		break;	case 2:		lcr |= Sl;		break;	default:		return -1;	} 	bits = uart->bits + ((lcr & Pen) ? 1 : 0) + ((lcr & Sl) ? 2 : 1);	lcr |= bits<<11; 	/* Set new value and reenable if device was previously enabled */	sp->smcmr = lcr; 	uart->stop = stop; 	return 0;} static intsmcbits(Uart* uart, int bits){	int lcr, b;	SMC *sp; 	if (bits < 5 || bits > 14)		return -1; 	sp = ((UartData*)uart->regs)->smc;	lcr = sp->smcmr & ~Clen; 	b = bits + ((sp->smcmr & Pen) ? 1 : 0) + ((sp->smcmr & Sl) ? 2 : 1); 	if (b > 15)		return -1; 	/* Disable transmitter/receiver */	sp->smcmr &= ~(Ren | Ten); 	/* Set new value and reenable if device was previously enabled */	sp->smcmr = lcr |  b<<11; 	uart->bits = bits; 	return 0;} static intsmcbaud(Uart* uart, int baud){	int i;	SMC *sp; 	if (uart->enabled){		sp = ((UartData*)uart->regs)->smc;			if(uart->freq == 0 || baud <= 0)			return -1;			i = sp - imm->smc;		imm->brgc[i] = (((m->brghz >> 4) / baud) << 1) | 0x00010000;	}	uart->baud = baud; 	return 0;} static voidsmcbreak(Uart*, int){} static voidsmckick(Uart *uart){	BD *txb;	UartData *ud;	int i; 	if(uart->blocked)		return; 	ud = uart->regs;	txb = ud->txb; 	if (txb->status & BDReady)		return;	/* Still busy */ 	for(i = 0; i < Txsize; i++){		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)			break;		ud->txbuf[i] = *(uart->op++);	}	if (i == 0)		return;	dcflush(ud->txbuf, Txsize);	txb->length = i;	sync();	txb->status |= BDReady|BDInt;} static voidsmcinterrupt(Ureg*, void* u){	int i, nc;	char *buf;	BD *rxb;	UartData *ud;	Uart *uart;	uchar events; 	uart = u;	if (uart == nil)		panic("uart is nil");	ud = uart->regs;	if (ud == nil)		panic("ud is nil"); 	events = ud->smc->smce;	ud->smc->smce = events;	/* Clear events */ 	if (events & 0x10)		iprint("smc%d: break\n", ud->smcno);	if (events & 0x4)

Lines 1–500 of 645.