From fff070f2cbb01b7c0879e9dcb13ee4e3ed2497f0 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 8 May 2022 16:50:29 +0000 Subject: imx8: add work in progress i.MX8MQ kernel for the mntreform2 laptop This is a work in progress port to the mntreform2 laptop. Working so far: - mmu (same as raspberry pi 3b+) - arm generic timer - gicv3 - uart1 - enet With access to the uart, one can netboot this kernel in u-boot using the following commands: > dhcp > bootm --- sys/src/9/imx8/uartimx.c | 383 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 sys/src/9/imx8/uartimx.c (limited to 'sys/src/9/imx8/uartimx.c') diff --git a/sys/src/9/imx8/uartimx.c b/sys/src/9/imx8/uartimx.c new file mode 100644 index 000000000..afc7d0096 --- /dev/null +++ b/sys/src/9/imx8/uartimx.c @@ -0,0 +1,383 @@ +#include "u.h" +#include "../port/lib.h" +#include "../port/error.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + URXD = 0x00/4, /* UART Receiver Register */ + RX_CHARRDY = 1<<15, + RX_ERR = 1<<14, + RX_OVRRUN = 1<<13, + RX_FRMERR = 1<<12, + RX_BRK = 1<<11, + RX_PRERR = 1<<10, + RX_DATA = 0xFF, + + UTXD = 0x40/4, /* UART Transmitter Register */ + TX_DATA = 0xFF, + + UCR1 = 0x80/4, /* UART Control Register 1 */ + CR1_ADEN = 1<<15, /* Automatic Baud Rate Detection Interrupt Enable */ + CR1_ADNR = 1<<14, /* Automatic Detection of Baud Rate */ + CR1_TRDYEN = 1<<13, /* Transmitter Ready Interrupt Enable */ + CR1_IDEN = 1<<12, /* Idle Condition Detected Interrupt Enable */ + + CR1_ICD_SHIFT = 10, /* Idle Condition Detect Mask */ + CR1_ICD_MASK = 3<regs; + + if(u->blocked) + return; + while(regs[USR1] & SR1_TRDY){ + if(u->op >= u->oe && uartstageoutput(u) == 0) + break; + regs[UTXD] = *(u->op++) & TX_DATA; + } +} + +static void +config(Uart *u) +{ + u32int cr2, *regs = u->regs; + + /* enable uart */ + regs[UCR1] = CR1_UARTEN; + + cr2 = CR2_SRST | CR2_IRTS | CR2_RXEN | CR2_TXEN; + switch(u->parity){ + case 'e': cr2 |= CR2_PREN | CR2_PREVEN; break; + case 'o': cr2 |= CR2_PREN | CR2_PRODD; break; + } + cr2 |= u->bits == 7 ? CR2_WS7 : CR2_WS8; + if(u->stop == 2) cr2 |= CR2_STPB; + regs[UCR2] = cr2; + regs[UCR3] = 0x7<<8 | CR3_RXDMUXSEL; + regs[UCR4] = 31<baud) / 1600)-1; + regs[UBMR] = (u->freq / 1600)-1; + + regs[UCR1] = CR1_UARTEN | CR1_TRDYEN | CR1_RRDYEN; +} + +static int +bits(Uart *u, int n) +{ + switch(n){ + case 8: + break; + case 7: + break; + default: + return -1; + } + u->bits = n; + config(u); + return 0; +} + +static int +stop(Uart *u, int n) +{ + switch(n){ + case 1: + break; + case 2: + break; + default: + return -1; + } + u->stop = n; + config(u); + return 0; +} + +static int +parity(Uart *u, int n) +{ + switch(n){ + case 'n': + break; + case 'e': + break; + case 'o': + break; + default: + return -1; + } + u->parity = n; + config(u); + return 0; +} + +static int +baud(Uart *u, int n) +{ + if(u->freq == 0 || n <= 0) + return -1; + u->baud = n; + config(u); + return 0; +} + +static void +rts(Uart*, int) +{ +} + +static void +dobreak(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 +interrupt(Ureg*, void *arg) +{ + Uart *uart = arg; + u32int v, *regs = (u32int*)uart->regs; + + while((v = regs[URXD]) & RX_CHARRDY) + uartrecv(uart, v & RX_DATA); + + uartkick(uart); +} + +static void +disable(Uart *u) +{ + u32int *regs = u->regs; + regs[UCR1] = 0; +} + +static void +enable(Uart *u, int ie) +{ + disable(u); + if(ie) intrenable(IRQuart1, interrupt, u, BUSUNKNOWN, u->name); + config(u); +} + +static void +donothing(Uart*, int) +{ +} + +static void +putc(Uart *u, int c) +{ + u32int *regs = u->regs; + + while((regs[USR1] & SR1_TRDY) == 0) + ; + regs[UTXD] = c & TX_DATA; +} + +static int +getc(Uart *u) +{ + u32int c, *regs = (u32int*)u->regs; + + do + c = regs[URXD]; + while((c & RX_CHARRDY) == 0); + return c & RX_DATA; +} + +void +uartconsinit(void) +{ + consuart = &uart1; + consuart->console = 1; + uartctl(consuart, "l8 pn s1"); + uartputs(kmesg.buf, kmesg.n); +} + +PhysUart imxphysuart = { + .name = "imx", + .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, +}; + -- cgit v1.2.3