summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc/virtex/console/consolelite.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/powerpc/virtex/console/consolelite.c')
-rw-r--r--bsps/powerpc/virtex/console/consolelite.c425
1 files changed, 425 insertions, 0 deletions
diff --git a/bsps/powerpc/virtex/console/consolelite.c b/bsps/powerpc/virtex/console/consolelite.c
new file mode 100644
index 0000000000..4d0b2db17f
--- /dev/null
+++ b/bsps/powerpc/virtex/console/consolelite.c
@@ -0,0 +1,425 @@
+/*
+ * This file contains the console driver for the xilinx uart lite.
+ *
+ * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
+ * COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland.
+ *
+ * Derived from libbsp/no_cpu/no_bsp/console.c and therefore also:
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+#include <assert.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <bsp/irq.h>
+
+#include <bsp.h>
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+
+#include RTEMS_XPARAMETERS_H
+
+/* Status Register Masks */
+#define PARITY_ERROR 0x80 /* Parity Error */
+#define FRAME_ERROR 0x40 /* Frame Error */
+#define OVERRUN_ERROR 0x20 /* Overrun Error */
+#define STATUS_REG_ERROR_MASK ( PARITY_ERROR | FRAME_ERROR | OVERRUN_ERROR )
+
+#define INTR_ENABLED 0x10 /* Interrupts are enabled */
+#define TX_FIFO_FULL 0x08 /* Transmit FIFO is full */
+#define TX_FIFO_EMPTY 0x04 /* Transmit FIFO is empty */
+#define RX_FIFO_FULL 0x02 /* Receive FIFO is full */
+#define RX_FIFO_VALID_DATA 0x01 /* Receive FIFO has valid data */
+/* Control Register Masks*/
+#define ENABLE_INTR 0x10 /* Enable interrupts */
+#define RST_RX_FIFO 0x02 /* Reset and clear RX FIFO */
+#define RST_TX_FIFO 0x01 /* Reset and clear TX FIFO */
+
+/* General Defines */
+#define TX_FIFO_SIZE 16
+#define RX_FIFO_SIZE 16
+
+
+
+
+#define RECV_REG 0
+#define TRAN_REG 4
+#define STAT_REG 8
+#define CTRL_REG 12
+
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_control(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+CTRL_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_status(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+STAT_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_read(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+RECV_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE void xlite_uart_write(uint32_t base, char ch)
+{
+ *(volatile uint32_t*)(base+TRAN_REG) = (uint32_t)ch;
+ return;
+}
+
+
+
+static int xlite_write_char(uint32_t base, char ch)
+{
+ uint32_t retrycount= 0, idler, status;
+
+ while( ((status = xlite_uart_status(base)) & TX_FIFO_FULL) != 0 )
+ {
+ ++retrycount;
+
+ /* uart tx is busy */
+ if( retrycount == 0x4000 )
+ {
+ /* retrycount is arbitrary- just make it big enough so the uart is sure to be timed out before it trips */
+ return -1;
+ }
+
+ /* spin for a bit so we can sample the register rather than
+ * continually reading it */
+ for( idler= 0; idler < 0x2000; idler++);
+ }
+
+ xlite_uart_write(base, ch);
+
+ return 1;
+}
+
+static void xlite_init(int minor )
+{
+ /* Nothing to do */
+}
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+static void xlite_interrupt_handler(void *arg)
+{
+ int minor = (int) arg;
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ console_data *cd = &Console_Port_Data[minor];
+ uint32_t base = ct->ulCtrlPort1;
+ uint32_t status = xlite_uart_status(base);
+
+ while ((status & RX_FIFO_VALID_DATA) != 0) {
+ char c = (char) xlite_uart_read(base);
+
+ rtems_termios_enqueue_raw_characters(cd->termios_data, &c, 1);
+
+ status = xlite_uart_status(base);
+ }
+
+ if (cd->bActive) {
+ rtems_termios_dequeue_characters(cd->termios_data, 1);
+ }
+}
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static int xlite_open(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ rtems_status_code sc;
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ /* clear status register */
+ *((volatile uint32_t*)(base+STAT_REG)) = 0;
+
+ /* clear control register; reset fifos */
+ *((volatile uint32_t*)(base+CTRL_REG)) = RST_RX_FIFO | RST_TX_FIFO;
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ *((volatile uint32_t*)(base+CTRL_REG)) = ENABLE_INTR;
+
+ sc = rtems_interrupt_handler_install(
+ ct->ulIntVector,
+ "xlite",
+ RTEMS_INTERRUPT_UNIQUE,
+ xlite_interrupt_handler,
+ (void *) minor
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ return 0;
+}
+
+static int xlite_close(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ rtems_status_code sc;
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ *((volatile uint32_t*)(base+CTRL_REG)) = 0;
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ sc = rtems_interrupt_handler_remove(
+ ct->ulIntVector,
+ xlite_interrupt_handler,
+ (void *) minor
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ return 0;
+}
+
+
+
+static int xlite_read_polled (int minor )
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+
+ unsigned int status = xlite_uart_status(base);
+
+ if(status & RX_FIFO_VALID_DATA)
+ return (int)xlite_uart_read(base);
+ else
+ return -1;
+}
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+
+static ssize_t xlite_write_interrupt_driven(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ console_data *cd = &Console_Port_Data[minor];
+
+ if (len > 0) {
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+
+ xlite_uart_write(base, buf[0]);
+
+ cd->bActive = true;
+ } else {
+ cd->bActive = false;
+ }
+
+ return 0;
+}
+
+#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static ssize_t xlite_write_buffer_polled(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+ int nwrite = 0;
+
+ /*
+ * poll each byte in the string out of the port.
+ */
+ while (nwrite < len)
+ {
+ if( xlite_write_char(base, *buf++) < 0 ) break;
+ nwrite++;
+ }
+
+ /*
+ * return the number of bytes written.
+ */
+ return nwrite;
+}
+
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static void xlite_write_char_polled(
+ int minor,
+ char c
+)
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+ xlite_write_char(base, c);
+ return;
+}
+
+static int xlite_set_attributes(int minor, const struct termios *t)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+
+
+
+
+
+
+static const console_fns xlite_fns_polled =
+{
+ .deviceProbe = libchip_serial_default_probe,
+ .deviceFirstOpen = xlite_open,
+ .deviceLastClose = xlite_close,
+ .deviceRead = xlite_read_polled,
+ .deviceInitialize = xlite_init,
+ .deviceWritePolled = xlite_write_char_polled,
+ .deviceSetAttributes = xlite_set_attributes,
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ .deviceWrite = xlite_write_interrupt_driven,
+ .deviceOutputUsesInterrupts = true
+#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+ .deviceWrite = xlite_write_buffer_polled,
+ .deviceOutputUsesInterrupts = false
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+};
+
+
+
+
+
+
+/*
+** Set ulCtrlPort1 to the base address of each UART Lite instance. Set in vhdl model.
+*/
+
+
+console_tbl Console_Configuration_Ports[] = {
+{
+ "/dev/ttyS0", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ STDIN_BASEADDRESS, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ #ifdef XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
+ .ulIntVector = XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
+ #else
+ .ulIntVector = 0
+ #endif
+},
+#ifdef XPAR_UARTLITE_1_BASEADDR
+{
+ "/dev/ttyS1", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_1_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+},
+#endif
+#ifdef XPAR_UARTLITE_2_BASEADDR
+{
+ "/dev/ttyS2", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_2_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+},
+#endif
+#ifdef XPAR_UARTLITE_2_BASEADDR
+{
+ "/dev/ttyS3", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_3_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+}
+#endif
+};
+
+unsigned long Console_Configuration_Count =
+ RTEMS_ARRAY_SIZE(Console_Configuration_Ports);
+
+
+#include <rtems/bspIo.h>
+
+static void outputChar(char ch)
+{
+ xlite_write_char_polled( 0, ch );
+}
+
+static int inputChar(void)
+{
+ return xlite_read_polled(0);
+}
+
+BSP_output_char_function_type BSP_output_char = outputChar;
+BSP_polling_getchar_function_type BSP_poll_char = inputChar;
+
+