ref: 6a3a3d69c67647db5d5176a7cf9ee68e9fce4352
parent: fe34e52d19aeeb04bc34114fda928b6afeb62253
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Thu Apr 11 09:21:06 EDT 2019
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.
--- a/sys/src/9/bcm/devarch.c
+++ b/sys/src/9/bcm/devarch.c
@@ -174,6 +174,34 @@
}
void
+uartconsinit(void)
+{
+ extern PhysUart *physuart[];
+ char *p, *cmd;
+ Uart *uart;
+ int i, n;
+
+ if((p = getconf("console")) == nil)
+ return;
+ i = strtoul(p, &cmd, 0);
+ if(p == cmd)
+ return;
+ /* we only have two possible uarts, the pl011 and aux */
+ for(n = 0; physuart[n] != nil; n++)
+ ;
+ if(i < 0 || i >= n)
+ return;
+ uart = physuart[i]->pnp();
+ if(!uart->enabled)
+ (*uart->phys->enable)(uart, 0);
+ uartctl(uart, "l8 pn s1");
+ if(*cmd != '\0')
+ uartctl(uart, cmd);
+ consuart = uart;
+ uart->console = 1;
+}
+
+void
okay(int on)
{
static int first;
--- a/sys/src/9/bcm/io.h
+++ b/sys/src/9/bcm/io.h
@@ -11,6 +11,7 @@
IRQi2c = 53,
IRQspi = 54,
IRQsdhost = 56,
+ IRQuart = 57,
IRQmmc = 62,
IRQbasic = 64,
--- a/sys/src/9/bcm/uartmini.c
+++ b/sys/src/9/bcm/uartmini.c
@@ -47,7 +47,7 @@
static Uart miniuart = {
.regs = (u32int*)AUXREGS,
- .name = "uart0",
+ .name = "uart1",
.freq = 250000000,
.baud = 115200,
.phys = &miniphysuart,
@@ -100,7 +100,7 @@
ap[MuCntl] = TxEn|RxEn;
baud(uart, uart->baud);
if(ie){
- intrenable(IRQaux, interrupt, uart, 0, "uart");
+ intrenable(IRQaux, interrupt, uart, 0, uart->name);
ap[MuIer] = RxIen|TxIen;
}else
ap[MuIer] = 0;
@@ -259,7 +259,7 @@
{
}
-void
+static void
putc(Uart*, int c)
{
u32int *ap;
@@ -272,7 +272,7 @@
;
}
-int
+static int
getc(Uart*)
{
u32int *ap;
@@ -283,38 +283,8 @@
return ap[MuIo] & 0xFF;
}
-void
-uartconsinit(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, "l8 pn s1");
- if(*cmd != '\0')
- uartctl(uart, cmd);
-
- consuart = uart;
- uart->console = 1;
-}
-
PhysUart miniphysuart = {
- .name = "miniuart",
+ .name = "mini",
.pnp = pnp,
.enable = enable,
.disable = disable,
--- /dev/null
+++ b/sys/src/9/bcm/uartpl011.c
@@ -1,0 +1,303 @@
+/*
+ * bcm2835 PL011 uart
+ */
+
+#include "u.h"
+#include "../port/lib.h"
+#include "../port/error.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+enum {
+ DR = 0x00>>2,
+ RSRECR = 0x04>>2,
+ FR = 0x18>>2,
+ TXFE = 1<<7,
+ RXFF = 1<<6,
+ TXFF = 1<<5,
+ RXFE = 1<<4,
+ BUSY = 1<<3,
+
+ ILPR = 0x20>>2,
+ IBRD = 0x24>>2,
+ FBRD = 0x28>>2,
+ LCRH = 0x2c>>2,
+ WLENM = 3<<5,
+ WLEN8 = 3<<5,
+ WLEN7 = 2<<5,
+ WLEN6 = 1<<5,
+ WLEN5 = 0<<5,
+ FEN = 1<<4, /* fifo enable */
+ STP2 = 1<<3, /* 2 stop bits */
+ EPS = 1<<2, /* even parity select */
+ PEN = 1<<1, /* parity enabled */
+ BRK = 1<<0, /* send break */
+
+ CR = 0x30>>2,
+ CTSEN = 1<<15,
+ RTSEN = 1<<14,
+ RTS = 1<<11,
+ RXE = 1<<9,
+ TXE = 1<<8,
+ LBE = 1<<7,
+ UARTEN = 1<<0,
+
+ IFLS = 0x34>>2,
+ IMSC = 0x38>>2,
+ TXIM = 1<<5,
+ RXIM = 1<<4,
+
+ RIS = 0x3c>>2,
+ MIS = 0x40>>2,
+ ICR = 0x44>>2,
+ DMACR = 0x48>>2,
+ ITCR = 0x80>>2,
+ ITIP = 0x84>>2,
+ ITOP = 0x88>>2,
+ TDR = 0x8c>>2,
+};
+
+extern PhysUart pl011physuart;
+
+static Uart pl011uart = {
+ .regs = (u32int*)(VIRTIO+0x201000),
+ .name = "uart0",
+ .freq = 250000000,
+ .baud = 115200,
+ .phys = &pl011physuart,
+};
+
+static Uart*
+pnp(void)
+{
+ return &pl011uart;
+}
+
+static void
+interrupt(Ureg*, void *arg)
+{
+ Uart *uart = arg;
+ u32int *reg = (u32int*)uart->regs;
+
+ coherence();
+ if((reg[FR] & TXFE) == 0)
+ uartkick(uart);
+ while((reg[FR] & RXFE) == 0)
+ uartrecv(uart, reg[DR] & 0xFF);
+ coherence();
+
+}
+
+static void
+enable(Uart *uart, int ie)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ reg[CR] = UARTEN | RXE | TXE;
+ if(ie){
+ intrenable(IRQuart, interrupt, uart, 0, uart->name);
+ reg[IMSC] = TXIM|RXIM;
+ } else {
+ reg[IMSC] = 0;
+ }
+}
+
+static void
+disable(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ reg[IMSC] = 0;
+ reg[CR] = 0;
+}
+
+static void
+kick(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->blocked)
+ return;
+ coherence();
+ while((reg[FR] & TXFF) == 0){
+ if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
+ break;
+ reg[DR] = *(uart->op++);
+ }
+ coherence();
+}
+
+static void
+dobreak(Uart *uart, int ms)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ reg[LCRH] |= BRK;
+ delay(ms);
+ reg[LCRH] &= ~BRK;
+}
+
+static int
+baud(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ if(uart->freq <= 0 || n <= 0)
+ return -1;
+
+ reg[IBRD] = (uart->freq >> 4) / n;
+ reg[FBRD] = (uart->freq >> 4) % n;
+ uart->baud = n;
+ return 0;
+}
+
+static int
+bits(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ switch(n){
+ case 8:
+ reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN8;
+ break;
+ case 7:
+ reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN7;
+ break;
+ case 6:
+ reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN6;
+ break;
+ case 5:
+ reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN5;
+ break;
+ default:
+ return -1;
+ }
+ uart->bits = n;
+ return 0;
+}
+
+static int
+stop(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ switch(n){
+ case 1:
+ reg[LCRH] &= ~STP2;
+ break;
+ case 2:
+ reg[LCRH] |= STP2;
+ break;
+ default:
+ return -1;
+ }
+ uart->stop = n;
+ return 0;
+}
+
+static int
+parity(Uart *uart, int n)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ switch(n){
+ case 'n':
+ reg[LCRH] &= ~PEN;
+ break;
+ case 'e':
+ reg[LCRH] |= EPS | PEN;
+ break;
+ case 'o':
+ reg[LCRH] = (reg[LCRH] & ~EPS) | PEN;
+ break;
+ default:
+ return -1;
+ }
+ uart->parity = n;
+ return 0;
+}
+
+static void
+modemctl(Uart *uart, int on)
+{
+ uart->modem = on;
+}
+
+static void
+rts(Uart*, int)
+{
+}
+
+static long
+status(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 void
+donothing(Uart*, int)
+{
+}
+
+static void
+putc(Uart *uart, int c)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & TXFF) != 0)
+ ;
+ reg[DR] = c & 0xFF;
+}
+
+static int
+getc(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ while((reg[FR] & RXFE) != 0)
+ ;
+ return reg[DR] & 0xFF;
+}
+
+PhysUart pl011physuart = {
+ .name = "pl011",
+ .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,
+};