433 lines · 6.3 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. */ /* * bcm2835 mini uart (UART1) */ #include "u.h"#include "../port/lib.h"#include "../port/error.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" #define GPIOREGS	(VIRTIO+0x200000)#define AUXREGS		(VIRTIO+0x215000)#define	OkLed		16#define	TxPin		14#define	RxPin		15 /* GPIO regs */enum {	Fsel0	= 0x00>>2,		FuncMask= 0x7,		Input	= 0x0,		Output	= 0x1,		Alt0	= 0x4,		Alt1	= 0x5,		Alt2	= 0x6,		Alt3	= 0x7,		Alt4	= 0x3,		Alt5	= 0x2,	Set0	= 0x1c>>2,	Clr0	= 0x28>>2,	Lev0	= 0x34>>2,	PUD	= 0x94>>2,		Off	= 0x0,		Pulldown= 0x1,		Pullup	= 0x2,	PUDclk0	= 0x98>>2,	PUDclk1	= 0x9c>>2,}; /* AUX regs */enum {	Irq	= 0x00>>2,		UartIrq	= 1<<0,	Enables	= 0x04>>2,		UartEn	= 1<<0,	MuIo	= 0x40>>2,	MuIer	= 0x44>>2,		RxIen	= 1<<0,		TxIen	= 1<<1,	MuIir	= 0x48>>2,	MuLcr	= 0x4c>>2,		Bitsmask= 3<<0,		Bits7	= 2<<0,		Bits8	= 3<<0,	MuMcr	= 0x50>>2,		RtsN	= 1<<1,	MuLsr	= 0x54>>2,		TxDone	= 1<<6,		TxRdy	= 1<<5,		RxRdy	= 1<<0,	MuCntl	= 0x60>>2,		CtsFlow	= 1<<3,		TxEn	= 1<<1,		RxEn	= 1<<0,	MuBaud	= 0x68>>2,}; extern PhysUart miniphysuart; static Uart miniuart = {	.regs	= (u32int*)AUXREGS,	.name	= "uart0",	.freq	= 250000000,	.phys	= &miniphysuart,}; voidgpiosel(uint pin, int func){		u32int *gp, *fsel;	int off; 	gp = (u32int*)GPIOREGS;	fsel = &gp[Fsel0 + pin/10];	off = (pin % 10) * 3;	*fsel = (*fsel & ~(FuncMask<<off)) | func<<off;} voidgpiopulloff(uint pin){	u32int *gp, *reg;	u32int mask; 	gp = (u32int*)GPIOREGS;	reg = &gp[PUDclk0 + pin/32];	mask = 1 << (pin % 32);	gp[PUD] = Off;	microdelay(1);	*reg = mask;	microdelay(1);	*reg = 0;} voidgpioout(uint pin, int set){	u32int *gp;	int v; 	gp = (u32int*)GPIOREGS;	v = set? Set0 : Clr0;	gp[v + pin/32] = 1 << (pin % 32);} intgpioin(uint pin){	u32int *gp; 	gp = (u32int*)GPIOREGS;	return (gp[Lev0 + pin/32] & (1 << (pin % 32))) != 0;} static voidinterrupt(Ureg*, void *arg){	Uart *uart;	u32int *ap; 	uart = arg;	ap = (u32int*)uart->regs; 	coherence();	if(0 && (ap[Irq] & UartIrq) == 0)		return;	if(ap[MuLsr] & TxRdy)		uartkick(uart);	if(ap[MuLsr] & RxRdy){		if(uart->console){			if(uart->opens == 1)				uart->putc = kbdcr2nl;			else				uart->putc = nil;		}		do{			uartrecv(uart, ap[MuIo] & 0xFF);		}while(ap[MuLsr] & RxRdy);	}	coherence();} static Uart*pnp(void){	Uart *uart; 	uart = &miniuart;	if(uart->console == 0)		kbdq = qopen(8*1024, 0, nil, nil);	return uart;} static voidenable(Uart *uart, int ie){	u32int *ap; 	ap = (u32int*)uart->regs;	delay(10);	gpiosel(TxPin, Alt5);	gpiosel(RxPin, Alt5);	gpiopulloff(TxPin);	gpiopulloff(RxPin);	ap[Enables] |= UartEn;	ap[MuIir] = 6;	ap[MuLcr] = Bits8;	ap[MuCntl] = TxEn|RxEn;	ap[MuBaud] = 250000000/(115200*8) - 1;	if(ie){		intrenable(IRQaux, interrupt, uart, 0, "uart");		ap[MuIer] = RxIen|TxIen;	}else		ap[MuIer] = 0;} static voiddisable(Uart *uart){	u32int *ap; 	ap = (u32int*)uart->regs;	ap[MuCntl] = 0;	ap[MuIer] = 0;} static voidkick(Uart *uart){	u32int *ap; 	ap = (u32int*)uart->regs;	if(uart->blocked)		return;	coherence();	while(ap[MuLsr] & TxRdy){		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)			break;		ap[MuIo] = *(uart->op++);	}	if(ap[MuLsr] & TxDone)		ap[MuIer] &= ~TxIen;	else		ap[MuIer] |= TxIen;	coherence();} /* TODO */static voiddobreak(Uart *uart, int ms){	USED(uart, ms);} static intbaud(Uart *uart, int n){	u32int *ap; 	ap = (u32int*)uart->regs;	if(uart->freq == 0 || n <= 0)		return -1;	ap[MuBaud] = (uart->freq + 4*n - 1) / (8 * n) - 1;	uart->baud = n;	return 0;} static intbits(Uart *uart, int n){	u32int *ap;	int set; 	ap = (u32int*)uart->regs;	switch(n){	case 7:		set = Bits7;		break;	case 8:		set = Bits8;		break;	default:		return -1;	}	ap[MuLcr] = (ap[MuLcr] & ~Bitsmask) | set;	uart->bits = n;	return 0;} static intstop(Uart *uart, int n){	if(n != 1)		return -1;	uart->stop = n;	return 0;} static intparity(Uart *uart, int n){	if(n != 'n')		return -1;	uart->parity = n;	return 0;} /* * cts/rts flow control *   need to bring signals to gpio pins before enabling this */ static voidmodemctl(Uart *uart, int on){	u32int *ap; 	ap = (u32int*)uart->regs;	if(on)		ap[MuCntl] |= CtsFlow;	else		ap[MuCntl] &= ~CtsFlow;	uart->modem = on;} static voidrts(Uart *uart, int on){	u32int *ap; 	ap = (u32int*)uart->regs;	if(on)		ap[MuMcr] &= ~RtsN;	else		ap[MuMcr] |= RtsN;} static longstatus(Uart *uart, void *buf, long n, long offset){	char *p; 	p = malloc(READSTR);	if(p == nil)		error(Enomem);	snprint(p, READSTR,		"b%d\n"		"dev(%d) type(%d) framing(%d) overruns(%d) "		"berr(%d) serr(%d)\n", 		uart->baud,		uart->dev,		uart->type,		uart->ferr,		uart->oerr,		uart->berr,		uart->serr	);	n = readstr(offset, buf, n, p);	free(p); 	return n;} static voiddonothing(Uart*, int){} voidputc(Uart*, int c){	u32int *ap; 	ap = (u32int*)AUXREGS;	while((ap[MuLsr] & TxRdy) == 0)		;	ap[MuIo] = c;	while((ap[MuLsr] & TxRdy) == 0)		;} intgetc(Uart*){	u32int *ap; 	ap = (u32int*)AUXREGS;	while((ap[MuLsr] & RxRdy) == 0)		;	return ap[MuIo] & 0xFF;} voiduartconsinit(void){	Uart *uart;	int n;	char *p, *cmd; 	if((p = getconf("console")) == nil)		return;	n = strtoul(p, &cmd, 0);	if(p == cmd)		return;	switch(n){	default:		return;	case 0:		uart = &miniuart;		break;	} 	if(!uart->enabled)		(*uart->phys->enable)(uart, 0);	uartctl(uart, "b9600 l8 pn s1");	if(*cmd != '\0')		uartctl(uart, cmd); 	consuart = uart;	uart->console = 1;} PhysUart miniphysuart = {	.name		= "miniuart",	.pnp		= pnp,	.enable		= enable,	.disable	= disable,	.kick		= kick,	.dobreak	= dobreak,	.baud		= baud,	.bits		= bits,	.stop		= stop,	.parity		= parity,	.modemctl	= donothing,	.rts		= rts,	.dtr		= donothing,	.status		= status,	.fifo		= donothing,	.getc		= getc,	.putc		= putc,}; voidokay(int on){	static int first; 	if(!first++)		gpiosel(OkLed, Output);	gpioout(OkLed, !on);}