428 lines · 5.9 KB · C
RawDownload
#include "u.h"#include "../port/lib.h"#include "../port/error.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h" /* * bcm2835 mini uart (UART1) */ #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;	int c; 	uart = arg;	ap = (u32int*)uart->regs; 	coherence();	if(0)if((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{			c = ap[MuIo]&0xFF;			uartrecv(uart, c);		}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) framing(%d) overruns(%d) "		"berr(%d) serr(%d)\n", 		uart->baud,		uart->dev,		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;	int c; 	ap = (u32int*)AUXREGS;	while((ap[MuLsr]&RxRdy) == 0)		;	c = ap[MuIo]&0xFF;	return c;} 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);}