summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/lib/libbsp/sparc/Makefile.am5
-rw-r--r--c/src/lib/libbsp/sparc/leon3/Makefile.am3
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/bsp.h1
-rw-r--r--c/src/lib/libbsp/sparc/leon3/include/leon.h37
-rw-r--r--c/src/lib/libbsp/sparc/leon3/preinstall.am4
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/cons.h42
-rw-r--r--c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h1
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c677
-rw-r--r--c/src/lib/libbsp/sparc/shared/uart/cons.c189
9 files changed, 958 insertions, 1 deletions
diff --git a/c/src/lib/libbsp/sparc/Makefile.am b/c/src/lib/libbsp/sparc/Makefile.am
index 67b62ca585..d733ca1c11 100644
--- a/c/src/lib/libbsp/sparc/Makefile.am
+++ b/c/src/lib/libbsp/sparc/Makefile.am
@@ -49,7 +49,10 @@ EXTRA_DIST += shared/include/grspw.h
EXTRA_DIST += shared/include/grspw_pci.h
EXTRA_DIST += shared/include/grspw_rasta.h
-# UART (APBUART)
+# UART
+EXTRA_DIST += shared/uart/cons.c
+EXTRA_DIST += shared/uart/apbuart_cons.c
+EXTRA_DIST += shared/include/cons.h
EXTRA_DIST += shared/uart/apbuart.c
EXTRA_DIST += shared/uart/apbuart_pci.c
EXTRA_DIST += shared/uart/apbuart_rasta.c
diff --git a/c/src/lib/libbsp/sparc/leon3/Makefile.am b/c/src/lib/libbsp/sparc/leon3/Makefile.am
index f57b24591b..f263ab607a 100644
--- a/c/src/lib/libbsp/sparc/leon3/Makefile.am
+++ b/c/src/lib/libbsp/sparc/leon3/Makefile.am
@@ -79,6 +79,9 @@ libbsp_a_SOURCES += ../../shared/clockdrv_shell.h
# console
libbsp_a_SOURCES += ../../shared/console-termios.c
libbsp_a_SOURCES += console/console.c
+libbsp_a_SOURCES += ../../sparc/shared/uart/cons.c
+libbsp_a_SOURCES += ../../sparc/shared/uart/apbuart_cons.c
+include_HEADERS += ../../sparc/shared/include/cons.h
# debugio
libbsp_a_SOURCES += console/printk_support.c
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index 37dfedb1e9..d302418774 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/bsp.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
@@ -255,6 +255,7 @@ extern const unsigned char LEON3_irq_to_cpu[32];
* image bigger.
*/
#define AMBAPPBUS_INFO_AVAIL /* AMBAPP Bus driver */
+#define APBUART_INFO_AVAIL /* APBUART Console driver */
#define GPTIMER_INFO_AVAIL /* GPTIMER Timer driver */
#ifdef __cplusplus
diff --git a/c/src/lib/libbsp/sparc/leon3/include/leon.h b/c/src/lib/libbsp/sparc/leon3/include/leon.h
index 6057c42f4b..8d7a03a3ac 100644
--- a/c/src/lib/libbsp/sparc/leon3/include/leon.h
+++ b/c/src/lib/libbsp/sparc/leon3/include/leon.h
@@ -87,6 +87,43 @@ extern "C" {
/* 0 = no function */
/*
+ * The following defines the bits in the UART Control Registers.
+ */
+
+#define LEON_REG_UART_CONTROL_RTD 0x000000FF /* RX/TX data */
+
+/*
+ * The following defines the bits in the LEON UART Status Register.
+ */
+
+#define LEON_REG_UART_STATUS_DR 0x00000001 /* Data Ready */
+#define LEON_REG_UART_STATUS_TSE 0x00000002 /* TX Send Register Empty */
+#define LEON_REG_UART_STATUS_THE 0x00000004 /* TX Hold Register Empty */
+#define LEON_REG_UART_STATUS_BR 0x00000008 /* Break Error */
+#define LEON_REG_UART_STATUS_OE 0x00000010 /* RX Overrun Error */
+#define LEON_REG_UART_STATUS_PE 0x00000020 /* RX Parity Error */
+#define LEON_REG_UART_STATUS_FE 0x00000040 /* RX Framing Error */
+#define LEON_REG_UART_STATUS_TF 0x00000200 /* FIFO Full */
+#define LEON_REG_UART_STATUS_ERR 0x00000078 /* Error Mask */
+
+/*
+ * The following defines the bits in the LEON UART Control Register.
+ */
+
+#define LEON_REG_UART_CTRL_RE 0x00000001 /* Receiver enable */
+#define LEON_REG_UART_CTRL_TE 0x00000002 /* Transmitter enable */
+#define LEON_REG_UART_CTRL_RI 0x00000004 /* Receiver interrupt enable */
+#define LEON_REG_UART_CTRL_TI 0x00000008 /* Transmitter interrupt enable */
+#define LEON_REG_UART_CTRL_PS 0x00000010 /* Parity select */
+#define LEON_REG_UART_CTRL_PE 0x00000020 /* Parity enable */
+#define LEON_REG_UART_CTRL_FL 0x00000040 /* Flow control enable */
+#define LEON_REG_UART_CTRL_LB 0x00000080 /* Loop Back enable */
+#define LEON_REG_UART_CTRL_DB 0x00000800 /* Debug FIFO enable */
+#define LEON_REG_UART_CTRL_SI 0x00004000 /* TX shift register empty IRQ enable */
+#define LEON_REG_UART_CTRL_FA 0x80000000 /* FIFO Available */
+#define LEON_REG_UART_CTRL_FA_BIT 31
+
+/*
* The following defines the bits in the LEON Cache Control Register.
*/
#define LEON3_REG_CACHE_CTRL_FI 0x00200000 /* Flush instruction cache */
diff --git a/c/src/lib/libbsp/sparc/leon3/preinstall.am b/c/src/lib/libbsp/sparc/leon3/preinstall.am
index 99c8b22604..a45fc31353 100644
--- a/c/src/lib/libbsp/sparc/leon3/preinstall.am
+++ b/c/src/lib/libbsp/sparc/leon3/preinstall.am
@@ -109,6 +109,10 @@ $(PROJECT_INCLUDE)/tlib.h: ../../sparc/shared/include/tlib.h $(PROJECT_INCLUDE)/
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tlib.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/tlib.h
+$(PROJECT_INCLUDE)/cons.h: ../../sparc/shared/include/cons.h $(PROJECT_INCLUDE)/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/cons.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/cons.h
+
$(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h
diff --git a/c/src/lib/libbsp/sparc/shared/include/cons.h b/c/src/lib/libbsp/sparc/shared/include/cons.h
new file mode 100644
index 0000000000..2f1e51704f
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/include/cons.h
@@ -0,0 +1,42 @@
+/* Console driver interface to UART drivers
+ *
+ * - First console device that has System Console flag set will be
+ * system console.
+ * - If none of the registered console devices has system console set,
+ * the first is registered device is used, unless it has
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef __CONS_H__
+#define __CONS_H__
+
+struct console_dev;
+
+#define CONSOLE_FLAG_SYSCON 0x01
+
+struct console_cons_ops {
+ void (*get_uart_attrs)(struct console_dev *, struct termios *t);
+};
+
+struct console_dev {
+ /* Set to non-zero if this UART should be system console and/or
+ * debug console.
+ */
+ int flags;
+ char *fsname; /* File system prefix */
+ const struct rtems_termios_callbacks *callbacks; /* TERMIOS Callbacks */
+ struct console_cons_ops ops;
+};
+
+extern void console_dev_register(struct console_dev *dev);
+#if 0
+extern void console_dev_unregister(struct console_dev *dev);
+#endif
+
+#endif
diff --git a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
index 23e8cbd3a9..c8fca2422f 100644
--- a/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
+++ b/c/src/lib/libbsp/sparc/shared/include/drvmgr/ambapp_bus.h
@@ -28,6 +28,7 @@ extern "C" {
DRIVER_ID(DRVMGR_BUS_TYPE_AMBAPP, ((((vendor) & 0xff) << 16) | ((device) & 0xfff)))
/*** Gaisler Hardware Device Driver IDs ***/
+#define DRIVER_AMBAPP_GAISLER_APBUART_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_APBUART)
#define DRIVER_AMBAPP_GAISLER_GPTIMER_ID DRIVER_AMBAPP_ID(VENDOR_GAISLER, GAISLER_GPTIMER)
struct amba_dev_id {
diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
new file mode 100644
index 0000000000..2785286406
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
@@ -0,0 +1,677 @@
+/* This file contains the driver for the GRLIB APBUART serial port. The driver
+ * is implemented by using the cons.c console layer. Interrupt/Polling/Task
+ * driven mode can be configured using driver resources:
+ *
+ * - mode (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode)
+ * - syscon (0=Force not Ssystem Console, 1=Suggest System Console)
+ *
+ * The BSP define APBUART_INFO_AVAIL in order to add the info routine
+ * used for debugging.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+/******************* Driver manager interface ***********************/
+#include <bsp.h>
+#include <rtems/libio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <rtems/bspIo.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <drvmgr/drvmgr.h>
+#include <drvmgr/ambapp_bus.h>
+#include <apbuart.h>
+#include <ambapp.h>
+#include <grlib.h>
+#include <cons.h>
+#include <rtems/termiostypes.h>
+
+/*#define DEBUG 1 */
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* LEON3 Low level transmit/receive functions provided by debug-uart code */
+extern void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent);
+extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
+extern struct apbuart_regs *dbg_uart; /* The debug UART */
+
+struct apbuart_priv {
+ struct console_dev condev;
+ struct drvmgr_dev *dev;
+ struct apbuart_regs *regs;
+ char devName[32];
+ void *cookie;
+ int sending;
+ int mode;
+};
+
+/* TERMIOS Layer Callback functions */
+void apbuart_get_attributes(struct console_dev *condev, struct termios *t);
+int apbuart_set_attributes(int minor, const struct termios *t);
+ssize_t apbuart_write_polled(int minor, const char *buf, size_t len);
+int apbuart_pollRead(int minor);
+ssize_t apbuart_write_intr(int minor, const char *buf, size_t len);
+int apbuart_pollRead_task(int minor);
+int apbuart_firstOpen(int major, int minor, void *arg);
+int apbuart_lastClose(int major, int minor, void *arg);
+
+void apbuart_isr(void *arg);
+int apbuart_get_baud(struct apbuart_priv *uart);
+
+int apbuart_init1(struct drvmgr_dev *dev);
+#ifdef APBUART_INFO_AVAIL
+static int apbuart_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int, char *argv[]);
+#define APBUART_INFO_FUNC apbuart_info
+#else
+#define APBUART_INFO_FUNC NULL
+#endif
+
+struct drvmgr_drv_ops apbuart_ops =
+{
+ .init = {apbuart_init1, NULL, NULL, NULL},
+ .remove = NULL,
+ .info = APBUART_INFO_FUNC
+};
+
+static struct amba_dev_id apbuart_ids[] =
+{
+ {VENDOR_GAISLER, GAISLER_APBUART},
+ {0, 0} /* Mark end of table */
+};
+
+static struct amba_drv_info apbuart_drv_info =
+{
+ {
+ DRVMGR_OBJ_DRV, /* Driver */
+ NULL, /* Next driver */
+ NULL, /* Device list */
+ DRIVER_AMBAPP_GAISLER_APBUART_ID, /* Driver ID */
+ "APBUART_DRV", /* Driver Name */
+ DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
+ &apbuart_ops,
+ NULL, /* Funcs */
+ 0, /* No devices yet */
+ sizeof(struct apbuart_priv), /*DrvMgr alloc private*/
+ },
+ &apbuart_ids[0]
+};
+
+void apbuart_cons_register_drv (void)
+{
+ DBG("Registering APBUART Console driver\n");
+ drvmgr_drv_register(&apbuart_drv_info.general);
+}
+
+/* Interrupt mode routines */
+static const rtems_termios_callbacks Callbacks_intr = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ NULL, /* pollRead */
+ apbuart_write_intr, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+};
+
+/* Polling mode routines */
+static const rtems_termios_callbacks Callbacks_task = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ apbuart_pollRead_task, /* pollRead */
+ apbuart_write_intr, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */
+};
+
+/* Polling mode routines */
+static const rtems_termios_callbacks Callbacks_poll = {
+ apbuart_firstOpen, /* firstOpen */
+ apbuart_lastClose, /* lastClose */
+ apbuart_pollRead, /* pollRead */
+ apbuart_write_polled, /* write */
+ apbuart_set_attributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_POLLED /* outputUsesInterrupts */
+};
+
+int apbuart_init1(struct drvmgr_dev *dev)
+{
+ struct apbuart_priv *priv;
+ struct amba_dev_info *ambadev;
+ struct ambapp_core *pnpinfo;
+ union drvmgr_key_value *value;
+ char prefix[32];
+ unsigned int db;
+ static int first_uart = 1;
+
+ /* The default operation in AMP is to use APBUART[0] for CPU[0],
+ * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
+ * since we don't know how many CPU-cores there are. Note this only
+ * affects the on-chip amba bus (the root bus). The user can override
+ * the default resource sharing by defining driver resources for the
+ * APBUART devices on each AMP OS instance.
+ */
+#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
+ if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
+ drvmgr_keys_get(dev, NULL) != 0) {
+ /* User hasn't configured on-chip APBUART, leave it untouched */
+ return DRVMGR_EBUSY;
+ }
+#endif
+
+ DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
+ /* Private data was allocated and zeroed by driver manager */
+ priv = dev->priv;
+ if (!priv)
+ return DRVMGR_NOMEM;
+ priv->dev = dev;
+
+ /* Get device information from AMBA PnP information */
+ ambadev = (struct amba_dev_info *)priv->dev->businfo;
+ if (ambadev == NULL)
+ return -1;
+ pnpinfo = &ambadev->info;
+ priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
+
+ /* Clear HW regs, leave baudrate register as it is */
+ priv->regs->status = 0;
+ /* leave debug bit, and Transmitter/receiver if this is the debug UART */
+#ifdef LEON3
+ if (priv->regs == dbg_uart) {
+ db = priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
+ LEON_REG_UART_CTRL_RE |
+ LEON_REG_UART_CTRL_TE |
+ LEON_REG_UART_CTRL_FL |
+ LEON_REG_UART_CTRL_PE |
+ LEON_REG_UART_CTRL_PS);
+ } else
+#endif
+ db = priv->regs->ctrl & LEON_REG_UART_CTRL_DB;
+
+ priv->regs->ctrl = db;
+
+ /* The system console and Debug console may depend on this device, so
+ * initialize it straight away.
+ *
+ * We default to have System Console on first APBUART, user may override
+ * this behaviour by setting the syscon option to 0.
+ */
+ if (drvmgr_on_rootbus(dev) && first_uart) {
+ priv->condev.flags = CONSOLE_FLAG_SYSCON;
+ first_uart = 0;
+ } else {
+ priv->condev.flags = 0;
+ }
+
+ value = drvmgr_dev_key_get(priv->dev, "syscon", KEY_TYPE_INT);
+ if (value) {
+ if (value->i)
+ priv->condev.flags |= CONSOLE_FLAG_SYSCON;
+ else
+ priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
+ }
+
+ priv->condev.fsname = NULL;
+ priv->condev.ops.get_uart_attrs = apbuart_get_attributes;
+
+ /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
+ value = drvmgr_dev_key_get(priv->dev, "mode", KEY_TYPE_INT);
+ if (value)
+ priv->mode = value->i;
+ else
+ priv->mode = TERMIOS_POLLED;
+ if (priv->mode == TERMIOS_IRQ_DRIVEN) {
+ priv->condev.callbacks = &Callbacks_intr;
+ } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
+ priv->condev.callbacks = &Callbacks_task;
+ } else {
+ priv->condev.callbacks = &Callbacks_poll;
+ }
+
+ /* Get Filesystem name prefix */
+ prefix[0] = '\0';
+ if (drvmgr_get_dev_prefix(dev, prefix)) {
+ /* Got special prefix, this means we have a bus prefix
+ * And we should use our "bus minor"
+ */
+ sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
+ priv->condev.fsname = priv->devName;
+ }
+
+ /* Register it as a console device, the console driver will register
+ * a termios device as well
+ */
+ console_dev_register(&priv->condev);
+
+ return DRVMGR_OK;
+}
+
+#ifdef APBUART_INFO_AVAIL
+static int apbuart_info(
+ struct drvmgr_dev *dev,
+ void (*print_line)(void *p, char *str),
+ void *p, int argc, char *argv[])
+{
+ struct apbuart_priv *priv = dev->priv;
+ char *str1;
+ char buf[64];
+
+ if (dev->priv == NULL)
+ return -DRVMGR_EINVAL;
+
+ if (priv->mode == TERMIOS_POLLED)
+ str1 = "TERMIOS_POLLED";
+ else if (priv->mode == TERMIOS_TASK_DRIVEN)
+ str1 = "TERMIOS_TASK_DRIVEN";
+ else if (priv->mode == TERMIOS_TASK_DRIVEN)
+ str1 = "TERMIOS_TASK_DRIVEN";
+ else
+ str1 = "BAD MODE";
+
+ sprintf(buf, "UART Mode: %s", str1);
+ print_line(p, buf);
+ if (priv->condev.fsname) {
+ sprintf(buf, "FS Name: %s", priv->condev.fsname);
+ print_line(p, buf);
+ }
+ sprintf(buf, "STATUS REG: 0x%x", priv->regs->status);
+ print_line(p, buf);
+ sprintf(buf, "CTRL REG: 0x%x", priv->regs->ctrl);
+ print_line(p, buf);
+ sprintf(buf, "SCALER REG: 0x%x baud rate %d",
+ priv->regs->scaler, apbuart_get_baud(priv));
+ print_line(p, buf);
+
+ return DRVMGR_OK;
+}
+#endif
+
+#ifndef LEON3
+/* This routine transmits a character, it will busy-wait until on character
+ * fits in the APBUART Transmit FIFO
+ */
+void apbuart_outbyte_polled(
+ struct apbuart_regs *regs,
+ unsigned char ch,
+ int do_cr_on_newline,
+ int wait_sent)
+{
+send:
+ while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) {
+ /* Lower bus utilization while waiting for UART */
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ asm volatile ("nop"::); asm volatile ("nop"::);
+ }
+ regs->data = (unsigned int) ch;
+
+ if ((ch == '\n') && do_cr_on_newline) {
+ ch = '\r';
+ goto send;
+ }
+
+ /* Wait until the character has been sent? */
+ if (wait_sent) {
+ while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
+ ;
+ }
+}
+
+/* This routine polls for one character, return EOF if no character is available */
+int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
+{
+ if (regs->status & LEON_REG_UART_STATUS_ERR) {
+ regs->status = ~LEON_REG_UART_STATUS_ERR;
+ }
+
+ if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
+ return EOF;
+
+ return (int)regs->data;
+}
+#endif
+
+int apbuart_firstOpen(int major, int minor, void *arg)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ rtems_libio_open_close_args_t *ioarg = arg;
+
+ if ( ioarg && ioarg->iop )
+ uart->cookie = ioarg->iop->data1;
+ else
+ uart->cookie = NULL;
+
+ /* Enable TX/RX */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
+
+ if (uart->mode != TERMIOS_POLLED) {
+ /* Register interrupt and enable it */
+ drvmgr_interrupt_register(uart->dev, 0, "apbuart",
+ apbuart_isr, uart);
+
+ uart->sending = 0;
+ /* Turn on RX interrupts */
+ uart->regs->ctrl |= LEON_REG_UART_CTRL_RI;
+ }
+
+ return 0;
+}
+
+int apbuart_lastClose(int major, int minor, void *arg)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ if (uart->mode != TERMIOS_POLLED) {
+ /* Turn off RX interrupts */
+ uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
+
+ /**** Flush device ****/
+ while (uart->sending) {
+ /* Wait until all data has been sent */
+ }
+
+ /* Disable and unregister interrupt handler */
+ drvmgr_interrupt_unregister(uart->dev, 0, apbuart_isr, uart);
+ }
+
+#ifdef LEON3
+ /* Disable TX/RX if not used for DEBUG */
+ if (uart->regs != dbg_uart)
+ uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE);
+#endif
+
+ return 0;
+}
+
+int apbuart_pollRead(int minor)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ return apbuart_inbyte_nonblocking(uart->regs);
+}
+
+int apbuart_pollRead_task(int minor)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ int c, tot;
+ char buf[32];
+
+ tot = 0;
+ while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
+ buf[tot] = c;
+ tot++;
+ if (tot > 31) {
+ rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
+ tot = 0;
+ }
+ }
+ if (tot > 0)
+ rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
+
+ return EOF;
+}
+
+struct apbuart_baud {
+ unsigned int num;
+ unsigned int baud;
+};
+struct apbuart_baud apbuart_baud_table[] = {
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+ {B19200, 19200},
+ {B38400, 38400},
+ {B57600, 57600},
+ {B115200, 115200},
+ {B230400, 230400},
+ {B460800, 460800},
+};
+#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
+
+int apbuart_baud_num2baud(unsigned int num)
+{
+ int i;
+
+ for(i=0; i<BAUD_NUM; i++)
+ if (apbuart_baud_table[i].num == num)
+ return apbuart_baud_table[i].baud;
+ return -1;
+}
+
+struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
+{
+ int i, diff;
+
+ for(i=0; i<BAUD_NUM-1; i++) {
+ diff = apbuart_baud_table[i+1].baud -
+ apbuart_baud_table[i].baud;
+ if (baud < (apbuart_baud_table[i].baud + diff/2))
+ return &apbuart_baud_table[i];
+ }
+ return &apbuart_baud_table[BAUD_NUM-1];
+}
+
+int apbuart_get_baud(struct apbuart_priv *uart)
+{
+ unsigned int core_clk_hz;
+ unsigned int scaler;
+
+ /* Get current scaler setting */
+ scaler = uart->regs->scaler;
+
+ /* Get APBUART core frequency */
+ drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
+
+ /* Calculate baud rate from generator "scaler" number */
+ return core_clk_hz / ((scaler + 1) * 8);
+}
+
+struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
+{
+ return apbuart_baud_find_closest(apbuart_get_baud(uart));
+}
+
+int apbuart_set_attributes(int minor, const struct termios *t)
+{
+ unsigned int core_clk_hz;
+ unsigned int scaler;
+ unsigned int ctrl;
+ int baud;
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ switch(t->c_cflag & CSIZE) {
+ default:
+ case CS5:
+ case CS6:
+ case CS7:
+ /* Hardware doesn't support other than CS8 */
+ return -1;
+ case CS8:
+ break;
+ }
+
+ /* Read out current value */
+ ctrl = uart->regs->ctrl;
+
+ switch(t->c_cflag & (PARENB|PARODD)){
+ case (PARENB|PARODD):
+ /* Odd parity */
+ ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
+ break;
+
+ case PARENB:
+ /* Even parity */
+ ctrl &= ~LEON_REG_UART_CTRL_PS;
+ ctrl |= LEON_REG_UART_CTRL_PE;
+ break;
+
+ default:
+ case 0:
+ case PARODD:
+ /* No Parity */
+ ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
+ }
+
+ if (!(t->c_cflag & CLOCAL))
+ ctrl |= LEON_REG_UART_CTRL_FL;
+ else
+ ctrl &= ~LEON_REG_UART_CTRL_FL;
+
+ /* Update new settings */
+ uart->regs->ctrl = ctrl;
+
+ /* Baud rate */
+ baud = apbuart_baud_num2baud(t->c_cflag & CBAUD);
+ if (baud > 0){
+ /* Get APBUART core frequency */
+ drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
+
+ /* Calculate Baud rate generator "scaler" number */
+ scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
+
+ /* Set new baud rate by setting scaler */
+ uart->regs->scaler = scaler;
+ }
+
+ return 0;
+}
+
+void apbuart_get_attributes(struct console_dev *condev, struct termios *t)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)condev;
+ unsigned int ctrl;
+ struct apbuart_baud *baud;
+
+ t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL|CBAUD);
+
+ /* Hardware support only CS8 */
+ t->c_cflag |= CS8;
+
+ /* Read out current parity */
+ ctrl = uart->regs->ctrl;
+ if (ctrl & LEON_REG_UART_CTRL_PE) {
+ if (ctrl & LEON_REG_UART_CTRL_PS)
+ t->c_cflag |= PARENB|PARODD; /* Odd parity */
+ else
+ t->c_cflag |= PARENB; /* Even parity */
+ }
+
+ if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
+ t->c_cflag |= CLOCAL;
+
+ baud = apbuart_get_baud_closest(uart);
+ t->c_cflag |= baud->num;
+}
+
+ssize_t apbuart_write_polled(int minor, const char *buf, size_t len)
+{
+ int nwrite = 0;
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+
+ while (nwrite < len) {
+ apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
+ nwrite++;
+ }
+ return nwrite;
+}
+
+ssize_t apbuart_write_intr(int minor, const char *buf, size_t len)
+{
+ struct apbuart_priv *uart = (struct apbuart_priv *)minor;
+ unsigned int oldLevel;
+ unsigned int ctrl;
+
+ rtems_interrupt_disable(oldLevel);
+
+ /* Enable TX interrupt */
+ ctrl = uart->regs->ctrl;
+ uart->regs->ctrl = ctrl | LEON_REG_UART_CTRL_TI;
+
+ if (ctrl & LEON_REG_UART_CTRL_FA) {
+ /* APBUART with FIFO.. Fill as many as FIFO allows */
+ uart->sending = 0;
+ while (((uart->regs->status & LEON_REG_UART_STATUS_TF) == 0) &&
+ (uart->sending < len)) {
+ uart->regs->data = *buf;
+ buf++;
+ uart->sending++;
+ }
+ } else {
+ /* start UART TX, this will result in an interrupt when done */
+ uart->regs->data = *buf;
+
+ uart->sending = 1;
+ }
+
+ rtems_interrupt_enable(oldLevel);
+
+ return 0;
+}
+
+/* Handle UART interrupts */
+void apbuart_isr(void *arg)
+{
+ struct apbuart_priv *uart = arg;
+ unsigned int status;
+ char data;
+ int cnt;
+
+ /* Get all received characters */
+ if (uart->mode == TERMIOS_TASK_DRIVEN) {
+ if ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR)
+ rtems_termios_rxirq_occured(uart->cookie);
+ } else {
+ while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
+ /* Data has arrived, get new data */
+ data = uart->regs->data;
+
+ /* Tell termios layer about new character */
+ rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
+ }
+ }
+
+ if (uart->sending && (status & LEON_REG_UART_STATUS_THE)) {
+ /* Sent the one char, we disable TX interrupts */
+ uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
+
+ /* Tell close that we sent everything */
+ cnt = uart->sending;
+ uart->sending = 0;
+
+ /* apbuart_write_intr() will get called from this function */
+ rtems_termios_dequeue_characters(uart->cookie, cnt);
+ }
+}
diff --git a/c/src/lib/libbsp/sparc/shared/uart/cons.c b/c/src/lib/libbsp/sparc/shared/uart/cons.c
new file mode 100644
index 0000000000..3de9f54062
--- /dev/null
+++ b/c/src/lib/libbsp/sparc/shared/uart/cons.c
@@ -0,0 +1,189 @@
+/* This file contains the TTY driver for the serial ports. The driver
+ * is layered so that different UART hardware can be used. It is implemented
+ * using the Driver Manager.
+ *
+ * This driver uses the termios pseudo driver.
+ *
+ * COPYRIGHT (c) 2010.
+ * Cobham Gaisler AB.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <bsp.h>
+#include <stdlib.h>
+#include <rtems/libio.h>
+#include <rtems/bspIo.h>
+#include <cons.h>
+
+#ifdef RTEMS_DRVMGR_STARTUP
+
+/* Note that it is not possible to use the interrupt mode of the driver
+ * together with the "old" APBUART and -u to GRMON. However the new
+ * APBUART core (from 1.0.17-b2710) has the GRMON debug bit and can
+ * handle interrupts.
+ */
+
+int console_initialized = 0;
+rtems_device_major_number console_major = 0;
+
+#define FLAG_SYSCON 0x01
+struct console_priv {
+ unsigned char flags; /* 0x1=SystemConsole */
+ unsigned char minor;
+ struct console_dev *dev;
+};
+
+#define CONSOLE_MAX BSP_NUMBER_OF_TERMIOS_PORTS
+struct console_priv cons[CONSOLE_MAX] = {{0,0},};
+
+/* Register Console to TERMIOS layer and initialize it */
+void console_dev_init(struct console_priv *con, int minor)
+{
+ char name[16], *fsname;
+ rtems_status_code status;
+
+ if (!con->dev->fsname) {
+ strcpy(name, "/dev/console_a");
+ /* Special console name and MINOR for SYSTEM CONSOLE */
+ if (minor == 0)
+ name[12] = '\0'; /* /dev/console */
+ name[13] += minor; /* when minor=0, this has no effect... */
+ fsname = name;
+ } else {
+ fsname = con->dev->fsname;
+ }
+ status = rtems_io_register_name(fsname, console_major, minor);
+ if ((minor == 0) && (status != RTEMS_SUCCESSFUL))
+ rtems_fatal_error_occurred(status);
+}
+
+void console_dev_register(struct console_dev *dev)
+{
+ int i, minor = 0;
+ struct console_priv *con = NULL;
+
+ if ((dev->flags & CONSOLE_FLAG_SYSCON) && !cons[0].dev) {
+ con = &cons[0];
+ con->flags = FLAG_SYSCON;
+ } else {
+ for (i=1; i<CONSOLE_MAX; i++) {
+ if (!cons[i].dev) {
+ con = &cons[i];
+ con->flags = 0;
+ minor = i;
+ break;
+ }
+ }
+ }
+ if (con == NULL) {
+ /* Not enough console structures */
+ return;
+ }
+
+ /* Assign Console */
+ con->dev = dev;
+ con->minor = minor;
+
+ /* Console layer is already initialized, that means that we can
+ * register termios interface directly.
+ */
+ if (console_initialized)
+ console_dev_init(con, minor);
+}
+
+#if 0
+void console_dev_unregister(struct console_dev *dev)
+{
+
+}
+#endif
+
+rtems_device_driver console_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ int i;
+
+ console_major = major;
+
+ rtems_termios_initialize();
+
+ /* Register all Console a file system device node */
+ for (i=0; i<CONSOLE_MAX; i++) {
+ if (cons[i].dev)
+ console_dev_init(&cons[i], i);
+ }
+
+ console_initialized = 1;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_device_driver console_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ rtems_status_code status;
+ struct termios term;
+
+ if ((minor >= CONSOLE_MAX) || !cons[minor].dev)
+ return RTEMS_INVALID_NUMBER;
+
+ status = rtems_termios_open(
+ major,
+ (int)cons[minor].dev,
+ arg,
+ cons[minor].dev->callbacks);
+
+ /* Inherit UART hardware parameters from bootloader on system console */
+ if ((status == RTEMS_SUCCESSFUL) && (cons[minor].flags & FLAG_SYSCON) &&
+ (cons[minor].dev->ops.get_uart_attrs != NULL)) {
+ if (tcgetattr(STDIN_FILENO, &term) >= 0) {
+ cons[minor].dev->ops.get_uart_attrs(cons[minor].dev,
+ &term);
+ term.c_oflag |= ONLCR;
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ }
+ }
+
+ return status;
+}
+
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_close(arg);
+}
+
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_read(arg);
+}
+
+rtems_device_driver console_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_write(arg);
+}
+
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg)
+{
+ return rtems_termios_ioctl(arg);
+}
+
+#endif