changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: bcm: add pl011 uart driver

changeset 7153: 7048df8bc401
parent 7152: e93129fc35e7
child 7154: 0573cdc3766b
author: cinap_lenrek@felloff.net
date: Thu, 11 Apr 2019 13:21:06 +0200
files: sys/src/9/bcm/devarch.c sys/src/9/bcm/io.h sys/src/9/bcm/uartmini.c sys/src/9/bcm/uartpl011.c
description: bcm: add pl011 uart driver

the raspi has two uarts, the pl011 and the mini. only one
can be used at a time due to pin muxing. the bcm kernel
uses the mini by default.
     1.1--- a/sys/src/9/bcm/devarch.c
     1.2+++ b/sys/src/9/bcm/devarch.c
     1.3@@ -174,6 +174,34 @@ archinit(void)
     1.4 }
     1.5 
     1.6 void
     1.7+uartconsinit(void)
     1.8+{
     1.9+	extern PhysUart *physuart[];
    1.10+	char *p, *cmd;
    1.11+	Uart *uart;
    1.12+	int i, n;
    1.13+
    1.14+	if((p = getconf("console")) == nil)
    1.15+		return;
    1.16+	i = strtoul(p, &cmd, 0);
    1.17+	if(p == cmd)
    1.18+		return;
    1.19+	/* we only have two possible uarts, the pl011 and aux */
    1.20+	for(n = 0; physuart[n] != nil; n++)
    1.21+		;
    1.22+	if(i < 0 || i >= n)
    1.23+		return;
    1.24+	uart = physuart[i]->pnp();
    1.25+	if(!uart->enabled)
    1.26+		(*uart->phys->enable)(uart, 0);
    1.27+	uartctl(uart, "l8 pn s1");
    1.28+	if(*cmd != '\0')
    1.29+		uartctl(uart, cmd);
    1.30+	consuart = uart;
    1.31+	uart->console = 1;
    1.32+}
    1.33+
    1.34+void
    1.35 okay(int on)
    1.36 {
    1.37 	static int first;
     2.1--- a/sys/src/9/bcm/io.h
     2.2+++ b/sys/src/9/bcm/io.h
     2.3@@ -11,6 +11,7 @@ enum {
     2.4 	IRQi2c		= 53,
     2.5 	IRQspi		= 54,
     2.6 	IRQsdhost	= 56,
     2.7+	IRQuart		= 57,
     2.8 	IRQmmc		= 62,
     2.9 
    2.10 	IRQbasic	= 64,
     3.1--- a/sys/src/9/bcm/uartmini.c
     3.2+++ b/sys/src/9/bcm/uartmini.c
     3.3@@ -47,7 +47,7 @@ extern PhysUart miniphysuart;
     3.4 
     3.5 static Uart miniuart = {
     3.6 	.regs	= (u32int*)AUXREGS,
     3.7-	.name	= "uart0",
     3.8+	.name	= "uart1",
     3.9 	.freq	= 250000000,
    3.10 	.baud	= 115200,
    3.11 	.phys	= &miniphysuart,
    3.12@@ -100,7 +100,7 @@ enable(Uart *uart, int ie)
    3.13 	ap[MuCntl] = TxEn|RxEn;
    3.14 	baud(uart, uart->baud);
    3.15 	if(ie){
    3.16-		intrenable(IRQaux, interrupt, uart, 0, "uart");
    3.17+		intrenable(IRQaux, interrupt, uart, 0, uart->name);
    3.18 		ap[MuIer] = RxIen|TxIen;
    3.19 	}else
    3.20 		ap[MuIer] = 0;
    3.21@@ -259,7 +259,7 @@ donothing(Uart*, int)
    3.22 {
    3.23 }
    3.24 
    3.25-void
    3.26+static void
    3.27 putc(Uart*, int c)
    3.28 {
    3.29 	u32int *ap;
    3.30@@ -272,7 +272,7 @@ putc(Uart*, int c)
    3.31 		;
    3.32 }
    3.33 
    3.34-int
    3.35+static int
    3.36 getc(Uart*)
    3.37 {
    3.38 	u32int *ap;
    3.39@@ -283,38 +283,8 @@ getc(Uart*)
    3.40 	return ap[MuIo] & 0xFF;
    3.41 }
    3.42 
    3.43-void
    3.44-uartconsinit(void)
    3.45-{
    3.46-	Uart *uart;
    3.47-	int n;
    3.48-	char *p, *cmd;
    3.49-
    3.50-	if((p = getconf("console")) == nil)
    3.51-		return;
    3.52-	n = strtoul(p, &cmd, 0);
    3.53-	if(p == cmd)
    3.54-		return;
    3.55-	switch(n){
    3.56-	default:
    3.57-		return;
    3.58-	case 0:
    3.59-		uart = &miniuart;
    3.60-		break;
    3.61-	}
    3.62-
    3.63-	if(!uart->enabled)
    3.64-		(*uart->phys->enable)(uart, 0);
    3.65-	uartctl(uart, "l8 pn s1");
    3.66-	if(*cmd != '\0')
    3.67-		uartctl(uart, cmd);
    3.68-
    3.69-	consuart = uart;
    3.70-	uart->console = 1;
    3.71-}
    3.72-
    3.73 PhysUart miniphysuart = {
    3.74-	.name		= "miniuart",
    3.75+	.name		= "mini",
    3.76 	.pnp		= pnp,
    3.77 	.enable		= enable,
    3.78 	.disable	= disable,
     4.1new file mode 100644
     4.2--- /dev/null
     4.3+++ b/sys/src/9/bcm/uartpl011.c
     4.4@@ -0,0 +1,303 @@
     4.5+/*
     4.6+ * bcm2835 PL011 uart
     4.7+ */
     4.8+
     4.9+#include "u.h"
    4.10+#include "../port/lib.h"
    4.11+#include "../port/error.h"
    4.12+#include "mem.h"
    4.13+#include "dat.h"
    4.14+#include "fns.h"
    4.15+#include "io.h"
    4.16+
    4.17+enum {
    4.18+	DR	=	0x00>>2,
    4.19+	RSRECR	=	0x04>>2,
    4.20+	FR	=	0x18>>2,
    4.21+		TXFE	= 1<<7,
    4.22+		RXFF	= 1<<6,
    4.23+		TXFF	= 1<<5,
    4.24+		RXFE	= 1<<4,
    4.25+		BUSY	= 1<<3,
    4.26+
    4.27+	ILPR	=	0x20>>2,
    4.28+	IBRD	=	0x24>>2,
    4.29+	FBRD	=	0x28>>2,
    4.30+	LCRH	=	0x2c>>2,
    4.31+		WLENM	= 3<<5,
    4.32+		WLEN8	= 3<<5,
    4.33+		WLEN7	= 2<<5,
    4.34+		WLEN6	= 1<<5,
    4.35+		WLEN5	= 0<<5,
    4.36+		FEN	= 1<<4,	/* fifo enable */
    4.37+		STP2	= 1<<3,	/* 2 stop bits */
    4.38+		EPS	= 1<<2,	/* even parity select */
    4.39+		PEN	= 1<<1,	/* parity enabled */
    4.40+		BRK	= 1<<0,	/* send break */
    4.41+
    4.42+	CR	=	0x30>>2,
    4.43+		CTSEN	= 1<<15,
    4.44+		RTSEN	= 1<<14,
    4.45+		RTS	= 1<<11,
    4.46+		RXE	= 1<<9,
    4.47+		TXE	= 1<<8,
    4.48+		LBE	= 1<<7,
    4.49+		UARTEN	= 1<<0,
    4.50+		
    4.51+	IFLS	=	0x34>>2,
    4.52+	IMSC	=	0x38>>2,
    4.53+		TXIM	= 1<<5,
    4.54+		RXIM	= 1<<4,
    4.55+
    4.56+	RIS	=	0x3c>>2,
    4.57+	MIS	=	0x40>>2,
    4.58+	ICR	=	0x44>>2,
    4.59+	DMACR	=	0x48>>2,
    4.60+	ITCR	=	0x80>>2,
    4.61+	ITIP	=	0x84>>2,
    4.62+	ITOP	=	0x88>>2,
    4.63+	TDR	=	0x8c>>2,
    4.64+};
    4.65+
    4.66+extern PhysUart pl011physuart;
    4.67+
    4.68+static Uart pl011uart = {
    4.69+	.regs	= (u32int*)(VIRTIO+0x201000),
    4.70+	.name	= "uart0",
    4.71+	.freq	= 250000000,
    4.72+	.baud	= 115200,
    4.73+	.phys	= &pl011physuart,
    4.74+};
    4.75+
    4.76+static Uart*
    4.77+pnp(void)
    4.78+{
    4.79+	return &pl011uart;
    4.80+}
    4.81+
    4.82+static void
    4.83+interrupt(Ureg*, void *arg)
    4.84+{
    4.85+	Uart *uart = arg;
    4.86+	u32int *reg = (u32int*)uart->regs;
    4.87+
    4.88+	coherence();
    4.89+	if((reg[FR] & TXFE) == 0)
    4.90+		uartkick(uart);
    4.91+	while((reg[FR] & RXFE) == 0)
    4.92+		uartrecv(uart, reg[DR] & 0xFF);
    4.93+	coherence();
    4.94+
    4.95+}
    4.96+
    4.97+static void
    4.98+enable(Uart *uart, int ie)
    4.99+{
   4.100+	u32int *reg = (u32int*)uart->regs;
   4.101+
   4.102+	reg[CR] = UARTEN | RXE | TXE;
   4.103+	if(ie){
   4.104+		intrenable(IRQuart, interrupt, uart, 0, uart->name);
   4.105+		reg[IMSC] = TXIM|RXIM;
   4.106+	} else {
   4.107+		reg[IMSC] = 0;
   4.108+	}
   4.109+}
   4.110+
   4.111+static void
   4.112+disable(Uart *uart)
   4.113+{
   4.114+	u32int *reg = (u32int*)uart->regs;
   4.115+
   4.116+	reg[IMSC] = 0;
   4.117+	reg[CR] = 0;
   4.118+}
   4.119+
   4.120+static void
   4.121+kick(Uart *uart)
   4.122+{
   4.123+	u32int *reg = (u32int*)uart->regs;
   4.124+
   4.125+	if(uart->blocked)
   4.126+		return;
   4.127+	coherence();
   4.128+	while((reg[FR] & TXFF) == 0){
   4.129+		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
   4.130+			break;
   4.131+		reg[DR] = *(uart->op++);
   4.132+	}
   4.133+	coherence();
   4.134+}
   4.135+
   4.136+static void
   4.137+dobreak(Uart *uart, int ms)
   4.138+{
   4.139+	u32int *reg = (u32int*)uart->regs;
   4.140+
   4.141+	reg[LCRH] |= BRK;
   4.142+	delay(ms);
   4.143+	reg[LCRH] &= ~BRK;
   4.144+}
   4.145+
   4.146+static int
   4.147+baud(Uart *uart, int n)
   4.148+{
   4.149+	u32int *reg = (u32int*)uart->regs;
   4.150+
   4.151+	if(uart->freq <= 0 || n <= 0)
   4.152+		return -1;
   4.153+
   4.154+	reg[IBRD] = (uart->freq >> 4) / n;
   4.155+	reg[FBRD] = (uart->freq >> 4) % n;
   4.156+	uart->baud = n;
   4.157+	return 0;
   4.158+}
   4.159+
   4.160+static int
   4.161+bits(Uart *uart, int n)
   4.162+{
   4.163+	u32int *reg = (u32int*)uart->regs;
   4.164+
   4.165+	switch(n){
   4.166+	case 8:
   4.167+		reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN8;
   4.168+		break;
   4.169+	case 7:
   4.170+		reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN7;
   4.171+		break;
   4.172+	case 6:
   4.173+		reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN6;
   4.174+		break;
   4.175+	case 5:
   4.176+		reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN5;
   4.177+		break;
   4.178+	default:
   4.179+		return -1;
   4.180+	}
   4.181+	uart->bits = n;
   4.182+	return 0;
   4.183+}
   4.184+
   4.185+static int
   4.186+stop(Uart *uart, int n)
   4.187+{
   4.188+	u32int *reg = (u32int*)uart->regs;
   4.189+
   4.190+	switch(n){
   4.191+	case 1:
   4.192+		reg[LCRH] &= ~STP2;
   4.193+		break;
   4.194+	case 2:
   4.195+		reg[LCRH] |= STP2;
   4.196+		break;
   4.197+	default:
   4.198+		return -1;
   4.199+	}
   4.200+	uart->stop = n;
   4.201+	return 0;
   4.202+}
   4.203+
   4.204+static int
   4.205+parity(Uart *uart, int n)
   4.206+{
   4.207+	u32int *reg = (u32int*)uart->regs;
   4.208+
   4.209+	switch(n){
   4.210+	case 'n':
   4.211+		reg[LCRH] &= ~PEN;
   4.212+		break;
   4.213+	case 'e':
   4.214+		reg[LCRH] |= EPS | PEN;
   4.215+		break;
   4.216+	case 'o':
   4.217+		reg[LCRH] = (reg[LCRH] & ~EPS) | PEN;
   4.218+		break;
   4.219+	default:
   4.220+		return -1;
   4.221+	}
   4.222+	uart->parity = n;
   4.223+	return 0;
   4.224+}
   4.225+
   4.226+static void
   4.227+modemctl(Uart *uart, int on)
   4.228+{
   4.229+	uart->modem = on;
   4.230+}
   4.231+
   4.232+static void
   4.233+rts(Uart*, int)
   4.234+{
   4.235+}
   4.236+
   4.237+static long
   4.238+status(Uart *uart, void *buf, long n, long offset)
   4.239+{
   4.240+	char *p;
   4.241+
   4.242+	p = malloc(READSTR);
   4.243+	if(p == nil)
   4.244+		error(Enomem);
   4.245+	snprint(p, READSTR,
   4.246+		"b%d\n"
   4.247+		"dev(%d) type(%d) framing(%d) overruns(%d) "
   4.248+		"berr(%d) serr(%d)\n",
   4.249+
   4.250+		uart->baud,
   4.251+		uart->dev,
   4.252+		uart->type,
   4.253+		uart->ferr,
   4.254+		uart->oerr,
   4.255+		uart->berr,
   4.256+		uart->serr
   4.257+	);
   4.258+	n = readstr(offset, buf, n, p);
   4.259+	free(p);
   4.260+
   4.261+	return n;
   4.262+}
   4.263+
   4.264+static void
   4.265+donothing(Uart*, int)
   4.266+{
   4.267+}
   4.268+
   4.269+static void
   4.270+putc(Uart *uart, int c)
   4.271+{
   4.272+	u32int *reg = (u32int*)uart->regs;
   4.273+
   4.274+	while((reg[FR] & TXFF) != 0)
   4.275+		;
   4.276+	reg[DR] = c & 0xFF;
   4.277+}
   4.278+
   4.279+static int
   4.280+getc(Uart *uart)
   4.281+{
   4.282+	u32int *reg = (u32int*)uart->regs;
   4.283+
   4.284+	while((reg[FR] & RXFE) != 0)
   4.285+		;
   4.286+	return reg[DR] & 0xFF;
   4.287+}
   4.288+
   4.289+PhysUart pl011physuart = {
   4.290+	.name		= "pl011",
   4.291+	.pnp		= pnp,
   4.292+	.enable		= enable,
   4.293+	.disable	= disable,
   4.294+	.kick		= kick,
   4.295+	.dobreak	= dobreak,
   4.296+	.baud		= baud,
   4.297+	.bits		= bits,
   4.298+	.stop		= stop,
   4.299+	.parity		= parity,
   4.300+	.modemctl	= donothing,
   4.301+	.rts		= rts,
   4.302+	.dtr		= donothing,
   4.303+	.status		= status,
   4.304+	.fifo		= donothing,
   4.305+	.getc		= getc,
   4.306+	.putc		= putc,
   4.307+};