tty: add support for Raspberry Pi 2 and 3
Co-Authored-By: Benjamin Dauphin <benjamin.dauphin@live.fr> Co-Authored-By: Gilles Henaux <gill.henaux@gmail.com>
This commit is contained in:
@@ -4,4 +4,12 @@
|
||||
HERE=${.CURDIR}/arch/${MACHINE_ARCH}
|
||||
.PATH: ${HERE}
|
||||
|
||||
SRCS += console.c keyboard.c rs232.c
|
||||
SRCS += console.c keyboard.c
|
||||
|
||||
.if ${BSP_NAME} == rpi
|
||||
SRCS += pl011.c
|
||||
.elif ${BSP_NAME} == omap
|
||||
SRCS += omap.c
|
||||
.else
|
||||
.error Unknown bsp ${BSP_NAME}
|
||||
.endif
|
||||
|
||||
583
minix/drivers/tty/tty/arch/earm/pl011.c
Normal file
583
minix/drivers/tty/tty/arch/earm/pl011.c
Normal file
@@ -0,0 +1,583 @@
|
||||
#include <minix/config.h>
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/vm.h>
|
||||
#include <minix/type.h>
|
||||
#include <minix/board.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <termios.h>
|
||||
#include "pl011_serial.h"
|
||||
#include "tty.h"
|
||||
|
||||
#if NR_RS_LINES > 0
|
||||
|
||||
#define UART_FREQ 48000000L /* timer frequency */
|
||||
#if 0
|
||||
#define DFLT_BAUD TSPEED_DEF /* default baud rate */
|
||||
#else
|
||||
#define DFLT_BAUD B115200 /* default baud rate */
|
||||
#endif
|
||||
|
||||
|
||||
#define RS_IBUFSIZE 40960 /* RS232 input buffer size */
|
||||
#define RS_OBUFSIZE 40960 /* RS232 output buffer size */
|
||||
|
||||
/* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer
|
||||
* exactly reaches high water, or when TTY requests it. Sending restarts
|
||||
* when the input buffer empties below the low watermark.
|
||||
*/
|
||||
#define RS_ILOWWATER (1 * RS_IBUFSIZE / 4)
|
||||
#define RS_IHIGHWATER (3 * RS_IBUFSIZE / 4)
|
||||
|
||||
/* Output buffer low watermark.
|
||||
* TTY is notified when the output buffer empties below the low watermark, so
|
||||
* it may continue filling the buffer if doing a large write.
|
||||
*/
|
||||
#define RS_OLOWWATER (1 * RS_OBUFSIZE / 4)
|
||||
|
||||
/* RS232 device structure, one per device. */
|
||||
typedef struct rs232 {
|
||||
tty_t *tty; /* associated TTY structure */
|
||||
|
||||
int icount; /* number of bytes in the input buffer */
|
||||
char *ihead; /* next free spot in input buffer */
|
||||
char *itail; /* first byte to give to TTY */
|
||||
char idevready; /* nonzero if we are ready to receive (RTS) */
|
||||
char cts; /* normally 0, but MS_CTS if CLOCAL is set */
|
||||
|
||||
unsigned char ostate; /* combination of flags: */
|
||||
#define ODONE 1 /* output completed (< output enable bits) */
|
||||
#define ORAW 2 /* raw mode for xoff disable (< enab. bits) */
|
||||
#define OWAKEUP 4 /* tty_wakeup() pending (asm code only) */
|
||||
#define ODEVREADY UART_MSR_CTS /* external device hardware ready (CTS) */
|
||||
#define OQUEUED 0x20 /* output buffer not empty */
|
||||
#define OSWREADY 0x40 /* external device software ready (no xoff) */
|
||||
#define ODEVHUP UART_MSR_DCD /* external device has dropped carrier */
|
||||
#define OSOFTBITS (ODONE | ORAW | OWAKEUP | OQUEUED | OSWREADY)
|
||||
/* user-defined bits */
|
||||
#if (OSOFTBITS | ODEVREADY | ODEVHUP) == OSOFTBITS
|
||||
/* a weak sanity check */
|
||||
#error /* bits are not unique */
|
||||
#endif
|
||||
unsigned char oxoff; /* char to stop output */
|
||||
char inhibited; /* output inhibited? (follows tty_inhibited) */
|
||||
char drain; /* if set drain output and reconfigure line */
|
||||
int ocount; /* number of bytes in the output buffer */
|
||||
char *ohead; /* next free spot in output buffer */
|
||||
char *otail; /* next char to output */
|
||||
|
||||
phys_bytes phys_base; /* UART physical base address (I/O map) */
|
||||
unsigned int reg_offset; /* UART register offset */
|
||||
unsigned int uartclk; /* UART clock rate */
|
||||
int rx_overrun_events;
|
||||
|
||||
int irq; /* irq for this line */
|
||||
int irq_hook_id; /* interrupt hook */
|
||||
int irq_hook_kernel_id; /* id as returned from sys_irqsetpolicy */
|
||||
|
||||
char ibuf[RS_IBUFSIZE]; /* input buffer */
|
||||
char obuf[RS_OBUFSIZE]; /* output buffer */
|
||||
} rs232_t;
|
||||
|
||||
static rs232_t rs_lines[NR_RS_LINES];
|
||||
|
||||
typedef struct uart_port {
|
||||
phys_bytes base_addr;
|
||||
int irq;
|
||||
} uart_port_t;
|
||||
|
||||
static uart_port_t bcm2835_ports[] = {
|
||||
{ PL011_UART0_BASE, 121 }, /* UART0 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static int rs_write(tty_t *tp, int try);
|
||||
static void rs_echo(tty_t *tp, int c);
|
||||
static int rs_ioctl(tty_t *tp, int try);
|
||||
static void rs_config(rs232_t *rs);
|
||||
static int rs_read(tty_t *tp, int try);
|
||||
static int rs_icancel(tty_t *tp, int try);
|
||||
static int rs_ocancel(tty_t *tp, int try);
|
||||
static void rs_ostart(rs232_t *rs);
|
||||
static int rs_break_on(tty_t *tp, int try);
|
||||
static int rs_break_off(tty_t *tp, int try);
|
||||
static int rs_close(tty_t *tp, int try);
|
||||
static int rs_open(tty_t *tp, int try);
|
||||
static void rs232_handler(rs232_t *rs);
|
||||
static void rs_reset(rs232_t *rs);
|
||||
|
||||
static inline unsigned int readw(vir_bytes addr);
|
||||
static inline unsigned int serial_in(rs232_t *rs, int offset);
|
||||
static inline void serial_out(rs232_t *rs, int offset, int val);
|
||||
static inline void writew(vir_bytes addr, int val);
|
||||
static void write_chars(rs232_t *rs);
|
||||
static void read_chars(rs232_t *rs);
|
||||
|
||||
static inline unsigned int
|
||||
readw(vir_bytes addr)
|
||||
{
|
||||
return *((volatile unsigned int *) addr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
writew(vir_bytes addr, int val)
|
||||
{
|
||||
*((volatile unsigned int *) addr) = val;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
serial_in(rs232_t *rs, int offset)
|
||||
{
|
||||
offset <<= rs->reg_offset;
|
||||
return readw(rs->phys_base + offset);
|
||||
}
|
||||
|
||||
static inline void
|
||||
serial_out(rs232_t *rs, int offset, int val)
|
||||
{
|
||||
offset <<= rs->reg_offset;
|
||||
writew(rs->phys_base + offset, val);
|
||||
}
|
||||
|
||||
static void
|
||||
rs_reset(rs232_t *rs)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
rs_write(register tty_t *tp, int try)
|
||||
{
|
||||
/* (*devwrite)() routine for RS232. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int r, count, ocount;
|
||||
|
||||
if (rs->inhibited != tp->tty_inhibited) {
|
||||
/* Inhibition state has changed. */
|
||||
rs->ostate |= OSWREADY;
|
||||
if (tp->tty_inhibited) rs->ostate &= ~OSWREADY;
|
||||
rs->inhibited = tp->tty_inhibited;
|
||||
}
|
||||
|
||||
if (rs->drain) {
|
||||
/* Wait for the line to drain then reconfigure and continue
|
||||
* output. */
|
||||
if (rs->ocount > 0) return 0;
|
||||
rs->drain = FALSE;
|
||||
rs_config(rs);
|
||||
}
|
||||
/* While there is something to do. */
|
||||
for (;;) {
|
||||
ocount = buflen(rs->obuf) - rs->ocount;
|
||||
count = bufend(rs->obuf) - rs->ohead;
|
||||
if (count > ocount) count = ocount;
|
||||
if (count > tp->tty_outleft) count = tp->tty_outleft;
|
||||
if (count == 0 || tp->tty_inhibited) {
|
||||
if (try) return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (try) return 1;
|
||||
|
||||
/* Copy from user space to the RS232 output buffer. */
|
||||
if (tp->tty_outcaller == KERNEL) {
|
||||
/* We're trying to print on kernel's behalf */
|
||||
memcpy(rs->ohead,
|
||||
(char *) tp->tty_outgrant + tp->tty_outcum,
|
||||
count);
|
||||
} else {
|
||||
if ((r = sys_safecopyfrom(tp->tty_outcaller,
|
||||
tp->tty_outgrant, tp->tty_outcum,
|
||||
(vir_bytes) rs->ohead, count)) != OK) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform output processing on the output buffer. */
|
||||
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count,
|
||||
&ocount);
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assume echoing messed up by output. */
|
||||
tp->tty_reprint = TRUE;
|
||||
|
||||
/* Bookkeeping. */
|
||||
rs->ocount += ocount;
|
||||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
tp->tty_outcum += count;
|
||||
if ((tp->tty_outleft -= count) == 0) {
|
||||
/* Output is finished, reply to the writer. */
|
||||
if (tp->tty_outcaller != KERNEL)
|
||||
chardriver_reply_task(tp->tty_outcaller,
|
||||
tp->tty_outid, tp->tty_outcum);
|
||||
tp->tty_outcum = 0;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
}
|
||||
if (tp->tty_outleft > 0 && tp->tty_termios.c_ospeed == B0) {
|
||||
/* Oops, the line has hung up. */
|
||||
if (tp->tty_outcaller != KERNEL)
|
||||
chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
|
||||
EIO);
|
||||
tp->tty_outleft = tp->tty_outcum = 0;
|
||||
tp->tty_outcaller = NONE;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
rs_echo(tty_t *tp, int character)
|
||||
{
|
||||
/* Echo one character. (Like rs_write, but only one character, optionally.) */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int count, ocount;
|
||||
|
||||
ocount = buflen(rs->obuf) - rs->ocount;
|
||||
if (ocount == 0) return; /* output buffer full */
|
||||
count = 1;
|
||||
*rs->ohead = character; /* add one character */
|
||||
|
||||
out_process(tp, rs->obuf, rs->ohead, bufend(rs->obuf), &count, &ocount);
|
||||
if (count == 0) return;
|
||||
|
||||
rs->ocount += ocount;
|
||||
rs_ostart(rs);
|
||||
if ((rs->ohead += ocount) >= bufend(rs->obuf))
|
||||
rs->ohead -= buflen(rs->obuf);
|
||||
}
|
||||
|
||||
static int
|
||||
rs_ioctl(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Reconfigure the line as soon as the output has drained. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
|
||||
rs->drain = TRUE;
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static void rs_config(rs232_t *rs)
|
||||
{
|
||||
rs->ostate = ODEVREADY | ORAW | OSWREADY; /* reads MSR */
|
||||
|
||||
/*
|
||||
* XXX: Disable FIFO otherwise only half of every received character
|
||||
* will trigger an interrupt.
|
||||
*/
|
||||
serial_out(rs, PL011_LCR_H, serial_in(rs, PL011_LCR_H) & ~PL011_FEN);
|
||||
/* Set interrupt levels */
|
||||
serial_out(rs, PL011_IFLS, 0x0);
|
||||
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
|
||||
panic("unable to enable interrupts");
|
||||
}
|
||||
|
||||
void
|
||||
rs_init(tty_t *tp)
|
||||
{
|
||||
/* Initialize RS232 for one line. */
|
||||
rs232_t *rs;
|
||||
int line;
|
||||
uart_port_t this_pl011;
|
||||
char l[10];
|
||||
struct minix_mem_range mr;
|
||||
|
||||
/* Associate RS232 and TTY structures. */
|
||||
line = tp - &tty_table[NR_CONS];
|
||||
|
||||
/* See if kernel debugging is enabled; if so, don't initialize this
|
||||
* serial line, making tty not look at the irq and returning ENXIO
|
||||
* for all requests on it from userland. (The kernel will use it.)
|
||||
*/
|
||||
if(env_get_param(SERVARNAME, l, sizeof(l)-1) == OK && atoi(l) == line){
|
||||
printf("TTY: rs232 line %d not initialized (used by kernel)\n",
|
||||
line);
|
||||
return;
|
||||
}
|
||||
|
||||
rs = tp->tty_priv = &rs_lines[line];
|
||||
rs->tty = tp;
|
||||
|
||||
/* Set up input queue. */
|
||||
rs->ihead = rs->itail = rs->ibuf;
|
||||
|
||||
this_pl011 = bcm2835_ports[line];
|
||||
if (this_pl011.base_addr == 0) return;
|
||||
|
||||
/* Configure memory access */
|
||||
mr.mr_base = rs->phys_base;
|
||||
mr.mr_limit = rs->phys_base + 0x1000;
|
||||
if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != OK) {
|
||||
panic("Unable to request access to UART memory");
|
||||
}
|
||||
rs->phys_base = (vir_bytes) vm_map_phys(SELF,
|
||||
(void *) this_pl011.base_addr, 0x1000);
|
||||
|
||||
if (rs->phys_base == (vir_bytes) MAP_FAILED) {
|
||||
panic("Unable to request access to UART memory");
|
||||
}
|
||||
rs->reg_offset = 0;
|
||||
|
||||
rs->uartclk = UART_FREQ;
|
||||
rs->ohead = rs->otail = rs->obuf;
|
||||
|
||||
/* Override system default baud rate. We do this because u-boot
|
||||
* configures the UART for a baud rate of 115200 b/s and the kernel
|
||||
* directly sends data over serial out upon boot up. If we then
|
||||
* suddenly change the settings, the output will be garbled during
|
||||
* booting.
|
||||
*/
|
||||
tp->tty_termios.c_ospeed = DFLT_BAUD;
|
||||
|
||||
/* Configure IRQ */
|
||||
rs->irq = this_pl011.irq;
|
||||
|
||||
/* callback with irq line number */
|
||||
rs->irq_hook_kernel_id = rs->irq_hook_id = line;
|
||||
|
||||
/*
|
||||
* sys_irqsetpolicy modifies irq_hook_kernel_id. this modified id
|
||||
* needs to be used in sys_irqenable and similar calls.
|
||||
*/
|
||||
if (sys_irqsetpolicy(rs->irq, 0, &rs->irq_hook_kernel_id) != OK) {
|
||||
printf("RS232: Couldn't obtain hook for irq %d\n", rs->irq);
|
||||
} else {
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK) {
|
||||
printf("RS232: Couldn't enable irq %d (hooked)\n",
|
||||
rs->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get called back we get called back using the original
|
||||
* hook_id bit set. e.g. if we register with hook_id 5 the callback
|
||||
* calls us with the 5 th bit set
|
||||
*/
|
||||
rs_irq_set |= (1 << (rs->irq_hook_id ));
|
||||
|
||||
/* Enable interrupts */
|
||||
rs_reset(rs);
|
||||
rs_config(rs);
|
||||
|
||||
/* Fill in TTY function hooks. */
|
||||
tp->tty_devread = rs_read;
|
||||
tp->tty_devwrite = rs_write;
|
||||
tp->tty_echo = rs_echo;
|
||||
tp->tty_icancel = rs_icancel;
|
||||
tp->tty_ocancel = rs_ocancel;
|
||||
tp->tty_ioctl = rs_ioctl;
|
||||
tp->tty_break_on = rs_break_on;
|
||||
tp->tty_break_off = rs_break_off;
|
||||
tp->tty_open = rs_open;
|
||||
tp->tty_close = rs_close;
|
||||
|
||||
serial_out(rs, PL011_IMSC, PL011_RXRIS);
|
||||
}
|
||||
|
||||
void
|
||||
rs_interrupt(message *m)
|
||||
{
|
||||
unsigned long irq_set;
|
||||
int line;
|
||||
rs232_t *rs;
|
||||
|
||||
irq_set = m->m_notify.interrupts;
|
||||
for (line = 0, rs = rs_lines; line < NR_RS_LINES; line++, rs++) {
|
||||
if ((irq_set & (1 << rs->irq_hook_id)) && (rs->phys_base != 0)) {
|
||||
rs232_handler(rs);
|
||||
if (sys_irqenable(&rs->irq_hook_kernel_id) != OK)
|
||||
panic("unable to enable interrupts");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
rs_icancel(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_ocancel(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Cancel pending output. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
|
||||
rs->ostate &= ~(ODONE | OQUEUED);
|
||||
rs->ocount = 0;
|
||||
rs->otail = rs->ohead;
|
||||
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_read(tty_t *tp, int try)
|
||||
{
|
||||
/* Process characters from the circular input buffer. */
|
||||
rs232_t *rs = tp->tty_priv;
|
||||
int icount, count, ostate;
|
||||
|
||||
if (!(tp->tty_termios.c_cflag & CLOCAL)) {
|
||||
if (try) return 1;
|
||||
|
||||
/* Send a SIGHUP if hangup detected. */
|
||||
ostate = rs->ostate;
|
||||
rs->ostate &= ~ODEVHUP; /* save ostate, clear DEVHUP */
|
||||
if (ostate & ODEVHUP) {
|
||||
sigchar(tp, SIGHUP, 1);
|
||||
tp->tty_termios.c_ospeed = B0;/* Disable further I/O.*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (try) {
|
||||
return(rs->icount > 0);
|
||||
}
|
||||
|
||||
while ((count = rs->icount) > 0) {
|
||||
icount = bufend(rs->ibuf) - rs->itail;
|
||||
if (count > icount) count = icount;
|
||||
|
||||
/* Perform input processing on (part of) the input buffer. */
|
||||
if ((count = in_process(tp, rs->itail, count)) == 0) break;
|
||||
rs->icount -= count;
|
||||
|
||||
if ((rs->itail += count) == bufend(rs->ibuf))
|
||||
rs->itail = rs->ibuf;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rs_ostart(rs232_t *rs)
|
||||
{
|
||||
/* Tell RS232 there is something waiting in the output buffer. */
|
||||
rs->ostate |= OQUEUED;
|
||||
write_chars(rs);
|
||||
|
||||
serial_out(rs, PL011_IMSC, PL011_TXRIS|PL011_RXRIS);
|
||||
}
|
||||
|
||||
static int
|
||||
rs_break_on(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Raise break condition */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_break_off(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Clear break condition */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
static int
|
||||
rs_open(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* Set the speed to 115200 by default */
|
||||
tp->tty_termios.c_ospeed = DFLT_BAUD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rs_close(tty_t *tp, int UNUSED(dummy))
|
||||
{
|
||||
/* The line is closed; optionally hang up. */
|
||||
return 0; /* dummy */
|
||||
}
|
||||
|
||||
/* Low level (interrupt) routines. */
|
||||
|
||||
static void
|
||||
rs232_handler(struct rs232 *rs)
|
||||
{
|
||||
/* Handle interrupt of a UART port */
|
||||
unsigned int ris;
|
||||
|
||||
ris = serial_in(rs, PL011_RIS);
|
||||
|
||||
if (ris & PL011_RXRIS) {
|
||||
/* Data ready interrupt */
|
||||
read_chars(rs);
|
||||
}
|
||||
rs->ostate |= ODEVREADY;
|
||||
if (ris & PL011_TXRIS) {
|
||||
/* Ready to send and space available */
|
||||
write_chars(rs);
|
||||
}
|
||||
|
||||
serial_out(rs, PL011_ICR, ris);
|
||||
}
|
||||
|
||||
static void
|
||||
read_chars(rs232_t *rs)
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
/* check the line status to know if there are more chars */
|
||||
while ((serial_in(rs, PL011_FR) & PL011_RXFE) == 0) {
|
||||
c = serial_in(rs, PL011_DR);
|
||||
if (!(rs->ostate & ORAW)) {
|
||||
if (c == rs->oxoff) {
|
||||
rs->ostate &= ~OSWREADY;
|
||||
} else if (!(rs->ostate & OSWREADY)) {
|
||||
rs->ostate = OSWREADY;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs->icount == buflen(rs->ibuf)) {
|
||||
/* no buffer space? keep reading */
|
||||
continue;
|
||||
}
|
||||
|
||||
++rs->icount;
|
||||
|
||||
*rs->ihead = c;
|
||||
if (++rs->ihead == bufend(rs->ibuf)) {
|
||||
rs->ihead = rs->ibuf;
|
||||
}
|
||||
|
||||
if (rs->icount == 1) {
|
||||
rs->tty->tty_events = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_chars(rs232_t *rs)
|
||||
{
|
||||
/*
|
||||
* If there is output to do and everything is ready, do it (local device is
|
||||
* known ready).
|
||||
* Notify TTY when the buffer goes empty.
|
||||
*/
|
||||
while ((rs->ostate >= (OQUEUED | OSWREADY)) && ((serial_in(rs, PL011_FR) & PL011_TXFF) == 0)) {
|
||||
/* Bit test allows ORAW and requires the others. */
|
||||
serial_out(rs, PL011_DR, *rs->otail);
|
||||
if (++rs->otail == bufend(rs->obuf))
|
||||
rs->otail = rs->obuf;
|
||||
if (--rs->ocount == 0) {
|
||||
serial_out(rs, PL011_IMSC, PL011_RXRIS);
|
||||
/* Turn on ODONE flag, turn off OQUEUED */
|
||||
rs->ostate ^= (ODONE | OQUEUED);
|
||||
rs->tty->tty_events = 1;
|
||||
|
||||
} else {
|
||||
if (rs->icount == RS_OLOWWATER)
|
||||
rs->tty->tty_events = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NR_RS_LINES > 0 */
|
||||
178
minix/drivers/tty/tty/arch/earm/pl011_serial.h
Normal file
178
minix/drivers/tty/tty/arch/earm/pl011_serial.h
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef _PL011_SERIAL_H
|
||||
#define _PL011_SERIAL_H
|
||||
|
||||
/* UART register map */
|
||||
#define PL011_UART0_BASE 0x3f201000 /* UART0 physical address */
|
||||
|
||||
/* UART registers */
|
||||
#define PL011_DR 0x000 /* Data register, */
|
||||
#define PL011_SR_CR 0x004 /* Receive status register/error clear register */
|
||||
#define PL011_FR 0x018 /* Flag register, */
|
||||
#define PL011_ILPR 0x020 /* IrDA low-power counter register */
|
||||
#define PL011_IBRD 0x024 /* Integer baud rate register */
|
||||
#define PL011_FBRD 0x028 /* Fractional baud rate register */
|
||||
#define PL011_LCR_H 0x02C /* Line control register, */
|
||||
#define PL011_CR 0x030 /* control register */
|
||||
#define PL011_IFLS 0x034 /* Interrupt FIFO level select register */
|
||||
#define PL011_IMSC 0x038 /* Interrupt mask set/clear register */
|
||||
#define PL011_RIS 0x03C /* Raw interrupt status register */
|
||||
#define PL011_MIS 0x040 /* Masked interrupt status register */
|
||||
#define PL011_ICR 0x044 /* Interrupt clear register */
|
||||
#define PL011_DMACR 0x048 /* DMA control register */
|
||||
|
||||
#define PL011_RXRIS 0x10
|
||||
#define PL011_TXRIS 0x20
|
||||
|
||||
#define PL011_RXFE 0x10
|
||||
#define PL011_TXFF 0x20
|
||||
|
||||
#define PL011_FEN 0x10
|
||||
|
||||
/* Line Control Register bits */
|
||||
// #define PL011_LCR_PEN 0x01 /* Enable parity */
|
||||
|
||||
// #define PL011_LCR_WLEN5 0x00 /* Wordlength 5 bits */ //TODO How to know the offset? 0x05
|
||||
// #define PL011_LCR_WLEN6 0x01 /* Wordlength 6 bits */
|
||||
// #define PL011_LCR_WLEN7 0x02 /* Wordlength 7 bits */
|
||||
// #define PL011_LCR_WLEN8 0x03 /* Wordlength 8 bits */
|
||||
|
||||
// Send break. If this bit is set to 1, a low-level is continually output on the UARTTXD output, after
|
||||
// completing transmission of the current character. For the proper execution of the break command, the
|
||||
// software must set this bit for at least two complete frames.
|
||||
// For normal use, this bit must be cleared to 0
|
||||
// #define PL011_LCR_BRK 0x00
|
||||
|
||||
|
||||
|
||||
/* Line Control Register bits */
|
||||
// #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
|
||||
|
||||
// #define UART_LCR_SBC 0x40 /* Set break control */
|
||||
|
||||
// #define UART_LCR_EPAR 0x10 /* Even parity select */
|
||||
|
||||
// #define UART_LCR_PARITY 0x08 /* Enable parity */
|
||||
|
||||
// #define UART_LCR_STOP 0x04 /* Stop bits; 0=1 bit, 1=2 bits */
|
||||
|
||||
// #define UART_LCR_WLEN5 0x00 /* Wordlength 5 bits */
|
||||
// #define UART_LCR_WLEN6 0x01 /* Wordlength 6 bits */
|
||||
// #define UART_LCR_WLEN7 0x02 /* Wordlength 7 bits */
|
||||
// #define UART_LCR_WLEN8 0x03 /* Wordlength 8 bits */
|
||||
|
||||
// #define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configuration Mode A */
|
||||
// #define UART_LCR_CONF_MODE_B 0xBF /* Configuration Mode B */
|
||||
|
||||
|
||||
|
||||
|
||||
//// PL011_IMSC /* Interrupt mask set/clear register */
|
||||
//// UARTIMSC
|
||||
|
||||
//// #define UART_IER_MSI 0x08 /* Modem status interrupt */
|
||||
//// UARTMSINTR ?? /* Modem status interrupt */
|
||||
|
||||
/* UART register map */
|
||||
// #define OMAP3_UART1_BASE 0x4806A000 /* UART1 physical address */
|
||||
// #define OMAP3_UART2_BASE 0x4806C000 /* UART2 physical address */
|
||||
// #define OMAP3_UART3_BASE 0x49020000 /* UART3 physical address */
|
||||
|
||||
// /* UART registers */
|
||||
// #define OMAP3_THR 0 /* Transmit holding register */
|
||||
// #define OMAP3_RHR 0 /* Receive holding register */
|
||||
// #define OMAP3_DLL 0 /* Divisor latches low */
|
||||
// #define OMAP3_DLH 1 /* Divisor latches high */
|
||||
// #define OMAP3_IER 1 /* Interrupt enable register */
|
||||
// #define OMAP3_IIR 2 /* Interrupt identification register */
|
||||
// #define OMAP3_EFR 2 /* Extended features register */
|
||||
// #define OMAP3_FCR 2 /* FIFO control register */
|
||||
// #define OMAP3_LCR 3 /* Line control register */
|
||||
// #define OMAP3_MCR 4 /* Modem control register */
|
||||
// #define OMAP3_LSR 5 /* Line status register */
|
||||
// #define OMAP3_MSR 6 /* Modem status register */
|
||||
// #define OMAP3_TCR 6
|
||||
// #define OMAP3_MDR1 0x08 /* Mode definition register 1 */
|
||||
// #define OMAP3_MDR2 0x09 /* Mode definition register 2 */
|
||||
// #define OMAP3_SCR 0x10 /* Supplementary control register */
|
||||
// #define OMAP3_SSR 0x11 /* Supplementary status register */
|
||||
// #define OMAP3_SYSC 0x15 /* System configuration register */
|
||||
// #define OMAP3_SYSS 0x16 /* System status register */
|
||||
|
||||
/* Enhanced Features Register bits */
|
||||
#define UART_EFR_ECB (1 << 4)/* Enhanced control bit */
|
||||
#define UART_EFR_AUTO_CTS (1 << 6)/* auto cts enable */
|
||||
#define UART_EFR_AUTO_RTS (1 << 7)/* auto rts enable */
|
||||
|
||||
/* Interrupt Enable Register bits */
|
||||
#define UART_IER_MSI 0x08 /* Modem status interrupt */
|
||||
#define UART_IER_RLSI 0x04 /* Receiver line status interrupt */
|
||||
#define UART_IER_THRI 0x02 /* Transmitter holding register int. */
|
||||
#define UART_IER_RDI 0x01 /* Receiver data interrupt */
|
||||
|
||||
/* FIFO control register */
|
||||
// #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
|
||||
// #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
|
||||
// #define OMAP_UART_FCR_TX_FIFO_TRIG_SHIFT 4
|
||||
// #define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4)
|
||||
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the fifo */
|
||||
#define UART_FCR_CLR_RCVR 0x02 /* Clear the RCVR FIFO */
|
||||
#define UART_FCR_CLR_XMIT 0x04 /* Clear the XMIT FIFO */
|
||||
|
||||
/* Interrupt Identification Register bits */
|
||||
#define UART_IIR_RDI 0x04 /* Data ready interrupt */
|
||||
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
|
||||
#define UART_IIR_NO_INT 0x01 /* No interrupt is pending */
|
||||
|
||||
/* Line Control Register bits */
|
||||
// #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
|
||||
// #define UART_LCR_SBC 0x40 /* Set break control */
|
||||
// #define UART_LCR_EPAR 0x10 /* Even parity select */
|
||||
// #define UART_LCR_PARITY 0x08 /* Enable parity */
|
||||
// #define UART_LCR_STOP 0x04 /* Stop bits; 0=1 bit, 1=2 bits */
|
||||
// #define UART_LCR_WLEN5 0x00 /* Wordlength 5 bits */
|
||||
// #define UART_LCR_WLEN6 0x01 /* Wordlength 6 bits */
|
||||
// #define UART_LCR_WLEN7 0x02 /* Wordlength 7 bits */
|
||||
// #define UART_LCR_WLEN8 0x03 /* Wordlength 8 bits */
|
||||
|
||||
#define UART_LCR_CONF_MODE_A UART_LCR_DLAB /* Configuration Mode A */
|
||||
#define UART_LCR_CONF_MODE_B 0xBF /* Configuration Mode B */
|
||||
|
||||
/* Line Status Register bits */
|
||||
#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
|
||||
#define UART_LSR_BI 0x10 /* Break condition */
|
||||
#define UART_LSR_DR 0x01 /* Data ready */
|
||||
|
||||
/* Modem Control Register bits */
|
||||
#define UART_MCR_TCRTLR 0x40 /* Access TCR/TLR */
|
||||
#define UART_MCR_OUT2 0x08 /* Out2 complement */
|
||||
#define UART_MCR_RTS 0x02 /* RTS complement */
|
||||
#define UART_MCR_DTR 0x01 /* DTR output low */
|
||||
|
||||
/* Mode Definition Register 1 bits */
|
||||
#define OMAP_MDR1_DISABLE 0x07
|
||||
#define OMAP_MDR1_MODE13X 0x03
|
||||
#define OMAP_MDR1_MODE16X 0x00
|
||||
|
||||
/* Modem Status Register bits */
|
||||
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
|
||||
#define UART_MSR_CTS 0x10 /* Clear to Send */
|
||||
#define UART_MSR_DDCD 0x08 /* Delta DCD */
|
||||
|
||||
/* Supplementary control Register bits */
|
||||
// #define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
|
||||
|
||||
/* System Control Register bits */
|
||||
#define UART_SYSC_SOFTRESET 0x02
|
||||
|
||||
/* System Status Register bits */
|
||||
#define UART_SYSS_RESETDONE 0x01
|
||||
|
||||
/* Line status register fields */
|
||||
// #define OMAP3_LSR_TX_FIFO_E (1 << 5) /* Transmit FIFO empty */
|
||||
// #define OMAP3_LSR_RX_FIFO_E (1 << 0) /* Receive FIFO empty */
|
||||
// #define OMAP3_LSR_RXOE (1 << 1) /* Overrun error.*/
|
||||
|
||||
/* Supplementary status register fields */
|
||||
// #define OMAP3_SSR_TX_FIFO_FULL (1 << 0) /* Transmit FIFO full */
|
||||
|
||||
#endif /* _PL011_SERIAL_H */
|
||||
Reference in New Issue
Block a user