forked from Imagelibrary/rtems
Directly use "static inline" which is available in C99 and later. This brings the RTEMS implementation closer to standard C. Close #3935.
426 lines
12 KiB
C
426 lines
12 KiB
C
/*
|
|
* 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
|
|
|
|
|
|
|
|
static inline uint32_t xlite_uart_control(uint32_t base)
|
|
{
|
|
uint32_t c = *((volatile uint32_t*)(base+CTRL_REG));
|
|
return c;
|
|
}
|
|
|
|
|
|
static inline uint32_t xlite_uart_status(uint32_t base)
|
|
{
|
|
uint32_t c = *((volatile uint32_t*)(base+STAT_REG));
|
|
return c;
|
|
}
|
|
|
|
|
|
static inline uint32_t xlite_uart_read(uint32_t base)
|
|
{
|
|
uint32_t c = *((volatile uint32_t*)(base+RECV_REG));
|
|
return c;
|
|
}
|
|
|
|
|
|
static inline 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;
|
|
|
|
|