ref: 3ca395a36c3c1b098433c7a47106e76f00aee324
parent: 4032db00a7a813e8f36b2755204b6863b4545906
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri May 3 17:34:20 EDT 2019
uartpl011: dont touch line control while uart is enabled
--- a/sys/src/9/bcm/uartpl011.c
+++ b/sys/src/9/bcm/uartpl011.c
@@ -82,35 +82,90 @@
u32int *reg = (u32int*)uart->regs;
coherence();
- if((reg[FR] & TXFE) == 0)
- uartkick(uart);
while((reg[FR] & RXFE) == 0)
uartrecv(uart, reg[DR] & 0xFF);
+ if((reg[FR] & TXFF) == 0)
+ uartkick(uart);
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
coherence();
+}
+static void
+disable(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* disable interrupt */
+ reg[IMSC] = 0;
+ coherence();
+
+ /* clear interrupt */
+ reg[ICR] = 1<<5 | 1<<6 | 1<<7 | 1<<8 | 1<<9 | 1<<10;
+ coherence();
+
+ /* wait for last transmission to complete */
+ while((reg[FR] & BUSY) != 0)
+ delay(1);
+
+ /* disable uart */
+ reg[CR] = 0;
+ coherence();
+
+ /* flush rx fifo */
+ reg[LCRH] &= ~FEN;
+ coherence();
}
static void
-enable(Uart *uart, int ie)
+uartoff(Uart *uart)
{
u32int *reg = (u32int*)uart->regs;
+ u32int im;
+ im = reg[IMSC];
+ disable(uart);
+ reg[IMSC] = im;
+}
+
+static void
+uarton(Uart *uart)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ /* enable fifo */
+ reg[LCRH] |= FEN;
+ coherence();
+
+ /* enable uart */
reg[CR] = UARTEN | RXE | TXE;
+ coherence();
+}
+
+static void
+enable(Uart *uart, int ie)
+{
+ u32int *reg = (u32int*)uart->regs;
+
+ disable(uart);
if(ie){
intrenable(IRQuart, interrupt, uart, 0, uart->name);
reg[IMSC] = TXIM|RXIM;
- } else {
- reg[IMSC] = 0;
}
+ uarton(uart);
}
static void
-disable(Uart *uart)
-{
+linectl(Uart *uart, u32int set, u32int clr)
+{
u32int *reg = (u32int*)uart->regs;
- reg[IMSC] = 0;
- reg[CR] = 0;
+ if(uart->enabled)
+ uartoff(uart);
+
+ reg[LCRH] = set | (reg[LCRH] & ~clr);
+
+ if(uart->enabled)
+ uarton(uart);
}
static void
@@ -132,11 +187,9 @@
static void
dobreak(Uart *uart, int ms)
{
- u32int *reg = (u32int*)uart->regs;
-
- reg[LCRH] |= BRK;
+ linectl(uart, BRK, 0);
delay(ms);
- reg[LCRH] &= ~BRK;
+ linectl(uart, 0, BRK);
}
static int
@@ -147,8 +200,15 @@
if(uart->freq <= 0 || n <= 0)
return -1;
+ if(uart->enabled)
+ uartoff(uart);
+
reg[IBRD] = (uart->freq >> 4) / n;
reg[FBRD] = (uart->freq >> 4) % n;
+
+ if(uart->enabled)
+ uarton(uart);
+
uart->baud = n;
return 0;
}
@@ -156,20 +216,18 @@
static int
bits(Uart *uart, int n)
{
- u32int *reg = (u32int*)uart->regs;
-
switch(n){
case 8:
- reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN8;
+ linectl(uart, WLEN8, WLENM);
break;
case 7:
- reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN7;
+ linectl(uart, WLEN7, WLENM);
break;
case 6:
- reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN6;
+ linectl(uart, WLEN6, WLENM);
break;
case 5:
- reg[LCRH] = (reg[LCRH] & ~WLENM) | WLEN5;
+ linectl(uart, WLEN5, WLENM);
break;
default:
return -1;
@@ -181,14 +239,12 @@
static int
stop(Uart *uart, int n)
{
- u32int *reg = (u32int*)uart->regs;
-
switch(n){
case 1:
- reg[LCRH] &= ~STP2;
+ linectl(uart, 0, STP2);
break;
case 2:
- reg[LCRH] |= STP2;
+ linectl(uart, STP2, 0);
break;
default:
return -1;
@@ -200,17 +256,15 @@
static int
parity(Uart *uart, int n)
{
- u32int *reg = (u32int*)uart->regs;
-
switch(n){
case 'n':
- reg[LCRH] &= ~PEN;
+ linectl(uart, 0, PEN);
break;
case 'e':
- reg[LCRH] |= EPS | PEN;
+ linectl(uart, EPS|PEN, 0);
break;
case 'o':
- reg[LCRH] = (reg[LCRH] & ~EPS) | PEN;
+ linectl(uart, PEN, EPS);
break;
default:
return -1;