forked from Imagelibrary/rtems
2006-06-02 Jay Monkman <jtm@lopingdog.com>
* Makefile.am, console/uart.c, startup/exit.c: Changed UART
driver to be interrupt driven, added support for both UARTs.
This commit is contained in:
@@ -34,7 +34,7 @@ startup_rel_CPPFLAGS = $(AM_CPPFLAGS)
|
|||||||
startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
startup_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||||
|
|
||||||
noinst_PROGRAMS += console.rel
|
noinst_PROGRAMS += console.rel
|
||||||
console_rel_SOURCES = console/uart.c ../../shared/console.c
|
console_rel_SOURCES = console/uart.c
|
||||||
console_rel_CPPFLAGS = $(AM_CPPFLAGS)
|
console_rel_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
console_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
|
||||||
|
|
||||||
|
|||||||
@@ -1,262 +1,454 @@
|
|||||||
/*
|
/*
|
||||||
* console driver for MC9328XML UARTs
|
* Console driver for MC9328XML UARTs.
|
||||||
*
|
*
|
||||||
* This driver uses the shared console driver in
|
* Written Jay Monkman <jtm@lopingdog.com>
|
||||||
* ...../libbsp/shared/console.c
|
* Copyright (c) 2005 by Loping Dog Embedded Systems
|
||||||
*
|
|
||||||
* If you want the driver to be interrupt driven, you
|
|
||||||
* need to write the ISR, and in the ISR insert the
|
|
||||||
* chars into termios's queue.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2004 Cogent Computer Systems
|
|
||||||
* Written by Jay Monkman <jtm@lopingdog.com>
|
|
||||||
*
|
*
|
||||||
* The license and distribution terms for this file may be
|
* The license and distribution terms for this file may be
|
||||||
* found in the file LICENSE in this distribution or at
|
* found in the file LICENSE in this distribution or at
|
||||||
*
|
* http://www.rtems.com/license
|
||||||
* http://www.OARcorp.com/rtems/license.html.
|
|
||||||
*
|
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
*/
|
*/
|
||||||
#include <bsp.h> /* Must be before libio.h */
|
#include <bsp.h>
|
||||||
#include <rtems/libio.h>
|
#include <rtems/libio.h>
|
||||||
#include <termios.h>
|
|
||||||
#include <rtems/bspIo.h>
|
|
||||||
|
|
||||||
/* Put the CPU (or UART) specific header file #include here */
|
|
||||||
#include <mc9328mxl.h>
|
|
||||||
#include <libchip/serial.h>
|
|
||||||
#include <libchip/sersupp.h>
|
#include <libchip/sersupp.h>
|
||||||
|
#include <rtems/error.h>
|
||||||
|
#include <rtems/bspIo.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <rtems/irq.h>
|
||||||
|
#include <irq.h>
|
||||||
|
#include <mc9328mxl.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Define this to use interrupt driver UART driver */
|
||||||
|
#define USE_INTERRUPTS 1
|
||||||
|
|
||||||
/* How many serial ports? */
|
/* How many serial ports? */
|
||||||
#define NUM_DEVS 2
|
#define NUM_DEVS 2
|
||||||
|
#define poll_write(c) imx_uart_poll_write_char(0, c)
|
||||||
|
#define poll_read() imx_uart_poll_read_char(0)
|
||||||
|
|
||||||
int uart_poll_read(int minor);
|
static int imx_uart_first_open(int, int, void *);
|
||||||
|
static int imx_uart_last_close(int, int, void *);
|
||||||
|
static int imx_uart_poll_read(int);
|
||||||
|
static int imx_uart_set_attrs(int, const struct termios *);
|
||||||
|
static void imx_uart_init(int minor);
|
||||||
|
static void imx_uart_set_baud(int, int);
|
||||||
|
static int imx_uart_poll_write(int, const char *, int);
|
||||||
|
|
||||||
int dbg_dly;
|
#if defined(USE_INTERRUPTS)
|
||||||
|
static void imx_uart_tx_isr(rtems_irq_hdl_param);
|
||||||
|
static void imx_uart_rx_isr(rtems_irq_hdl_param);
|
||||||
|
static void imx_uart_isr_on(const rtems_irq_connect_data *irq);
|
||||||
|
static void imx_uart_isr_off(const rtems_irq_connect_data *irq);
|
||||||
|
static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq);
|
||||||
|
static int imx_uart_intr_write(int, const char *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* static function prototypes */
|
|
||||||
static int uart_first_open(int major, int minor, void *arg);
|
|
||||||
static int uart_last_close(int major, int minor, void *arg);
|
|
||||||
static int uart_read(int minor);
|
|
||||||
static int uart_write(int minor, const char *buf, int len);
|
|
||||||
static void uart_init(int minor);
|
|
||||||
static void uart_write_polled(int minor, char c);
|
|
||||||
static int uart_set_attributes(int minor, const struct termios *t);
|
|
||||||
|
|
||||||
/* These are used by code in console.c */
|
|
||||||
unsigned long Console_Port_Count = NUM_DEVS;
|
|
||||||
console_data Console_Port_Data[NUM_DEVS];
|
|
||||||
|
|
||||||
/* rtems console uses the following minor number */
|
/* TERMIOS callbacks */
|
||||||
rtems_device_minor_number Console_Port_Minor = 0;
|
#if defined(USE_INTERRUPTS)
|
||||||
|
rtems_termios_callbacks imx_uart_cbacks = {
|
||||||
/* Pointers to functions for handling the UART. */
|
.firstOpen = imx_uart_first_open,
|
||||||
console_fns uart_fns =
|
.lastClose = imx_uart_last_close,
|
||||||
{
|
.pollRead = NULL,
|
||||||
libchip_serial_default_probe,
|
.write = imx_uart_intr_write,
|
||||||
uart_first_open,
|
.setAttributes = imx_uart_set_attrs,
|
||||||
uart_last_close,
|
.stopRemoteTx = NULL,
|
||||||
uart_read,
|
.startRemoteTx = NULL,
|
||||||
uart_write,
|
.outputUsesInterrupts = 1,
|
||||||
uart_init,
|
|
||||||
uart_write_polled, /* not used in this driver */
|
|
||||||
uart_set_attributes,
|
|
||||||
FALSE /* TRUE if interrupt driven, FALSE if not. */
|
|
||||||
};
|
};
|
||||||
|
#else
|
||||||
/*
|
rtems_termios_callbacks imx_uart_cbacks = {
|
||||||
* There's one item in array for each UART.
|
.firstOpen = imx_uart_first_open,
|
||||||
*
|
.lastClose = imx_uart_last_close,
|
||||||
* Some of these fields are marked "NOT USED". They are not used
|
.pollRead = imx_uart_poll_read,
|
||||||
* by console.c, but may be used by drivers in libchip
|
.write = imx_uart_poll_write,
|
||||||
*
|
.setAttributes = imx_uart_set_attrs,
|
||||||
*/
|
.stopRemoteTx = NULL,
|
||||||
console_tbl Console_Port_Tbl[] = {
|
.startRemoteTx = NULL,
|
||||||
{
|
.outputUsesInterrupts = 0,
|
||||||
"/dev/com0", /* sDeviceName */
|
|
||||||
SERIAL_CUSTOM, /* deviceType */
|
|
||||||
&uart_fns, /* pDeviceFns */
|
|
||||||
NULL, /* deviceProbe */
|
|
||||||
NULL, /* pDeviceFlow */
|
|
||||||
0, /* ulMargin - NOT USED */
|
|
||||||
0, /* ulHysteresis - NOT USED */
|
|
||||||
NULL, /* pDeviceParams */
|
|
||||||
0, /* ulCtrlPort1 - NOT USED */
|
|
||||||
0, /* ulCtrlPort2 - NOT USED */
|
|
||||||
0, /* ulDataPort - NOT USED */
|
|
||||||
NULL, /* getRegister - NOT USED */
|
|
||||||
NULL, /* setRegister - NOT USED */
|
|
||||||
NULL, /* getData - NOT USED */
|
|
||||||
NULL, /* setData - NOT USED */
|
|
||||||
0, /* ulClock - NOT USED */
|
|
||||||
0 /* ulIntVector - NOT USED */
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/dev/com1", /* sDeviceName */
|
|
||||||
SERIAL_CUSTOM, /* deviceType */
|
|
||||||
&uart_fns, /* pDeviceFns */
|
|
||||||
NULL, /* deviceProbe */
|
|
||||||
NULL, /* pDeviceFlow */
|
|
||||||
0, /* ulMargin - NOT USED */
|
|
||||||
0, /* ulHysteresis - NOT USED */
|
|
||||||
NULL, /* pDeviceParams */
|
|
||||||
0, /* ulCtrlPort1 - NOT USED */
|
|
||||||
0, /* ulCtrlPort2 - NOT USED */
|
|
||||||
0, /* ulDataPort - NOT USED */
|
|
||||||
NULL, /* getRegister - NOT USED */
|
|
||||||
NULL, /* setRegister - NOT USED */
|
|
||||||
NULL, /* getData - NOT USED */
|
|
||||||
NULL, /* setData - NOT USED */
|
|
||||||
0, /* ulClock - NOT USED */
|
|
||||||
0 /* ulIntVector - NOT USED */
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/*********************************************************************/
|
#if defined(USE_INTERRUPTS)
|
||||||
/* Functions called via termios callbacks (i.e. the ones in uart_fns */
|
static rtems_irq_connect_data imx_uart_tx_isr_data[NUM_DEVS];
|
||||||
/*********************************************************************/
|
static rtems_irq_connect_data imx_uart_rx_isr_data[NUM_DEVS];
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
typedef struct {
|
||||||
* This is called the first time each device is opened. If the driver
|
int minor;
|
||||||
* is interrupt driven, you should enable interrupts here. Otherwise,
|
mc9328mxl_uart_regs_t * regs;
|
||||||
* it's probably safe to do nothing.
|
volatile const char *buf;
|
||||||
*
|
volatile int len;
|
||||||
* Since micromonitor already set up the UART, we do nothing.
|
volatile int idx;
|
||||||
*/
|
void *tty;
|
||||||
static int uart_first_open(int major, int minor, void *arg)
|
} imx_uart_data_t;
|
||||||
{
|
|
||||||
return 0;
|
static imx_uart_data_t imx_uart_data[NUM_DEVS];
|
||||||
}
|
|
||||||
|
rtems_device_driver console_initialize(
|
||||||
|
rtems_device_major_number major,
|
||||||
/*
|
rtems_device_minor_number minor,
|
||||||
* This is called the last time each device is closed. If the driver
|
void *arg
|
||||||
* is interrupt driven, you should disable interrupts here. Otherwise,
|
)
|
||||||
* it's probably safe to do nothing.
|
|
||||||
*/
|
|
||||||
static int uart_last_close(int major, int minor, void *arg)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read one character from UART.
|
|
||||||
*
|
|
||||||
* Return -1 if there's no data, otherwise return
|
|
||||||
* the character in lowest 8 bits of returned int.
|
|
||||||
*/
|
|
||||||
static int uart_read(int minor)
|
|
||||||
{
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if (minor == 0) {
|
|
||||||
if (MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_RDR) {
|
|
||||||
c = MC9328MXL_UART1_RXD & MC9328MXL_UART_RXD_CHARMASK;
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (minor == 1) {
|
|
||||||
if (MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_RDR) {
|
|
||||||
c = MC9328MXL_UART2_RXD & MC9328MXL_UART_RXD_CHARMASK;
|
|
||||||
return c;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printk("Unknown console minor number: %d\n", minor);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write buffer to UART
|
|
||||||
*
|
|
||||||
* return 1 on success, -1 on error
|
|
||||||
*/
|
|
||||||
static int uart_write(int minor, const char *buf, int len)
|
|
||||||
{
|
{
|
||||||
|
rtems_status_code status;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_DEVS; i++) {
|
||||||
|
imx_uart_init(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtems_termios_initialize();
|
||||||
|
|
||||||
|
/* /dev/console and /dev/tty0 are the same */
|
||||||
|
status = rtems_io_register_name("/dev/console", major, 0);
|
||||||
|
if (status != RTEMS_SUCCESSFUL) {
|
||||||
|
rtems_panic("%s:%d Error registering /dev/console :: %d\n",
|
||||||
|
__FUNCTION__, __LINE__, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = rtems_io_register_name("/dev/tty0", major, 0);
|
||||||
|
if (status != RTEMS_SUCCESSFUL) {
|
||||||
|
rtems_panic("%s:%d Error registering /dev/tty0 :: %d\n",
|
||||||
|
__FUNCTION__, __LINE__, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = rtems_io_register_name("/dev/tty1", major, 1);
|
||||||
|
if (status != RTEMS_SUCCESSFUL) {
|
||||||
|
rtems_panic("%s:%d Error registering /dev/tty1 :: %d\n",
|
||||||
|
__FUNCTION__, __LINE__, status);
|
||||||
|
}
|
||||||
|
return RTEMS_SUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtems_device_driver console_open(
|
||||||
|
rtems_device_major_number major,
|
||||||
|
rtems_device_minor_number minor,
|
||||||
|
void * arg
|
||||||
|
)
|
||||||
|
{
|
||||||
|
rtems_status_code rc;
|
||||||
|
|
||||||
|
if (minor > (NUM_DEVS - 1)) {
|
||||||
|
return RTEMS_INVALID_NUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = rtems_termios_open(major, minor, arg, &imx_uart_cbacks);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imx_uart_init(int minor)
|
||||||
|
{
|
||||||
|
imx_uart_data[minor].minor = minor;
|
||||||
|
imx_uart_data[minor].buf = NULL;
|
||||||
|
imx_uart_data[minor].len = 0;
|
||||||
|
imx_uart_data[minor].idx = 0;
|
||||||
|
|
||||||
if (minor == 0) {
|
if (minor == 0) {
|
||||||
for (i = 0; i < len; i++) {
|
#if defined(USE_INTERRUPTS)
|
||||||
/* Wait for fifo to have room */
|
imx_uart_tx_isr_data[minor].name = BSP_INT_UART1_TX;
|
||||||
while(!(MC9328MXL_UART1_SR2 & MC9328MXL_UART_SR2_TXDC)) {
|
imx_uart_rx_isr_data[minor].name = BSP_INT_UART1_RX;
|
||||||
continue;
|
#endif
|
||||||
}
|
imx_uart_data[minor].regs =
|
||||||
|
(mc9328mxl_uart_regs_t *) MC9328MXL_UART1_BASE;
|
||||||
MC9328MXL_UART1_TXD = (char) buf[i];
|
|
||||||
}
|
|
||||||
} else if (minor == 1) {
|
} else if (minor == 1) {
|
||||||
for (i = 0; i < len; i++) {
|
#if defined(USE_INTERRUPTS)
|
||||||
/* Wait for fifo to have room */
|
imx_uart_tx_isr_data[minor].name = BSP_INT_UART2_TX;
|
||||||
while(!(MC9328MXL_UART2_SR2 & MC9328MXL_UART_SR2_TXDC)) {
|
imx_uart_rx_isr_data[minor].name = BSP_INT_UART2_RX;
|
||||||
continue;
|
#endif
|
||||||
|
imx_uart_data[minor].regs =
|
||||||
|
(mc9328mxl_uart_regs_t *) MC9328MXL_UART2_BASE;
|
||||||
|
} else {
|
||||||
|
rtems_panic("%s:%d Unknown UART minor number %d\n",
|
||||||
|
__FUNCTION__, __LINE__, minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
MC9328MXL_UART2_TXD = (char) buf[i];
|
#if defined(USE_INTERRUPTS)
|
||||||
}
|
imx_uart_tx_isr_data[minor].hdl = imx_uart_tx_isr;
|
||||||
|
imx_uart_tx_isr_data[minor].handle = &imx_uart_data[minor];
|
||||||
|
imx_uart_tx_isr_data[minor].on = imx_uart_isr_on;
|
||||||
|
imx_uart_tx_isr_data[minor].off = imx_uart_isr_off;
|
||||||
|
imx_uart_tx_isr_data[minor].isOn = imx_uart_isr_is_on;
|
||||||
|
|
||||||
|
imx_uart_rx_isr_data[minor].hdl = imx_uart_rx_isr;
|
||||||
|
imx_uart_rx_isr_data[minor].handle = &imx_uart_data[minor];
|
||||||
|
imx_uart_rx_isr_data[minor].on = imx_uart_isr_on;
|
||||||
|
imx_uart_rx_isr_data[minor].off = imx_uart_isr_off;
|
||||||
|
imx_uart_rx_isr_data[minor].isOn = imx_uart_isr_is_on;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr1 = (
|
||||||
|
MC9328MXL_UART_CR1_UARTCLKEN |
|
||||||
|
MC9328MXL_UART_CR1_UARTEN);
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr2 = (
|
||||||
|
MC9328MXL_UART_CR2_IRTS |
|
||||||
|
MC9328MXL_UART_CR2_WS |
|
||||||
|
MC9328MXL_UART_CR2_TXEN |
|
||||||
|
MC9328MXL_UART_CR2_RXEN |
|
||||||
|
MC9328MXL_UART_CR2_SRST);
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr3 = 0;
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr4 = 0;
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->fcr = (
|
||||||
|
MC9328MXL_UART_FCR_TXTL(32) |
|
||||||
|
MC9328MXL_UART_FCR_RFDIV_1 |
|
||||||
|
MC9328MXL_UART_FCR_RXTL(1));
|
||||||
|
|
||||||
|
imx_uart_set_baud(minor, 38400);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_uart_first_open(int major, int minor, void *arg)
|
||||||
|
{
|
||||||
|
rtems_libio_open_close_args_t *args = arg;
|
||||||
|
|
||||||
|
imx_uart_data[minor].tty = args->iop->data1;
|
||||||
|
|
||||||
|
#if defined(USE_INTERRUPTS)
|
||||||
|
BSP_install_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
|
||||||
|
BSP_install_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_RRDYEN;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_uart_last_close(int major, int minor, void *arg)
|
||||||
|
{
|
||||||
|
#if defined(USE_INTERRUPTS)
|
||||||
|
BSP_remove_rtems_irq_handler(&imx_uart_tx_isr_data[minor]);
|
||||||
|
BSP_remove_rtems_irq_handler(&imx_uart_rx_isr_data[minor]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int imx_uart_poll_read(int minor)
|
||||||
|
{
|
||||||
|
if (imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_RDR) {
|
||||||
|
return imx_uart_data[minor].regs->rxd & 0xff;
|
||||||
} else {
|
} else {
|
||||||
printk("Unknown console minor number: %d\n", minor);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int imx_uart_poll_write(int minor, const char *buf, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
/* Wait for there to be room in the fifo */
|
||||||
|
while (!(imx_uart_data[minor].regs->sr2 & MC9328MXL_UART_SR2_TXDC)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->txd = buf[i];
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(USE_INTERRUPTS)
|
||||||
|
static int imx_uart_intr_write(int minor, const char *buf, int len)
|
||||||
|
{
|
||||||
|
imx_uart_data[minor].buf = buf;
|
||||||
|
imx_uart_data[minor].len = len;
|
||||||
|
imx_uart_data[minor].idx = 0;
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->cr1 |= MC9328MXL_UART_CR1_TXMPTYEN;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Set up the UART. */
|
|
||||||
static void uart_init(int minor)
|
|
||||||
{
|
|
||||||
/* leave the debug sio port as setup by umon */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* I'm not sure this is needed for the shared console driver. */
|
|
||||||
static void uart_write_polled(int minor, char c)
|
|
||||||
{
|
|
||||||
uart_write(minor, &c, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is for setting baud rate, bits, etc. */
|
/* This is for setting baud rate, bits, etc. */
|
||||||
static int uart_set_attributes(int minor, const struct termios *t)
|
static int imx_uart_set_attrs(int minor, const struct termios *t)
|
||||||
{
|
{
|
||||||
|
int baud;
|
||||||
|
|
||||||
|
baud = termios_baud_to_number(t->c_cflag & CBAUD);
|
||||||
|
imx_uart_set_baud(minor, baud);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************/
|
#if defined(USE_INTERRUPTS)
|
||||||
/*
|
static void imx_uart_isr_on(const rtems_irq_connect_data *irq)
|
||||||
* The following functions are not used by TERMIOS, but other RTEMS
|
|
||||||
* functions use them instead.
|
|
||||||
*/
|
|
||||||
/***********************************************************************/
|
|
||||||
/*
|
|
||||||
* Read from UART. This is used in the exit code, and can't
|
|
||||||
* rely on interrupts.
|
|
||||||
*/
|
|
||||||
int uart_poll_read(int minor)
|
|
||||||
{
|
{
|
||||||
return uart_read(minor);
|
MC9328MXL_AITC_INTENNUM = irq->name;
|
||||||
}
|
}
|
||||||
|
static void imx_uart_isr_off(const rtems_irq_connect_data *irq)
|
||||||
|
{
|
||||||
/*
|
MC9328MXL_AITC_INTDISNUM = irq->name;
|
||||||
* Write a character to the console. This is used by printk() and
|
}
|
||||||
* maybe other low level functions. It should not use interrupts or any
|
static int imx_uart_isr_is_on(const rtems_irq_connect_data *irq)
|
||||||
* RTEMS system calls. It needs to be very simple
|
{
|
||||||
*/
|
int irq_num = (int)irq->name;
|
||||||
static void _BSP_put_char( char c ) {
|
if (irq_num < 32) {
|
||||||
uart_write_polled(0, c);
|
return MC9328MXL_AITC_INTENABLEL & (1 << irq_num);
|
||||||
if (c == '\n') {
|
} else {
|
||||||
uart_write_polled(0, '\r');
|
return MC9328MXL_AITC_INTENABLEH & (1 << (irq_num - 32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BSP_output_char_function_type BSP_output_char = _BSP_put_char;
|
static void imx_uart_rx_isr(rtems_irq_hdl_param param)
|
||||||
|
{
|
||||||
|
imx_uart_data_t *uart_data = param;
|
||||||
|
char buf[32];
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
while (uart_data->regs->sr2 & MC9328MXL_UART_SR2_RDR) {
|
||||||
|
buf[i] = uart_data->regs->rxd & 0xff;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtems_termios_enqueue_raw_characters(uart_data->tty, buf, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void imx_uart_tx_isr(rtems_irq_hdl_param param)
|
||||||
|
{
|
||||||
|
imx_uart_data_t *uart_data = param;
|
||||||
|
int len;
|
||||||
|
int minor = uart_data->minor;
|
||||||
|
|
||||||
|
|
||||||
|
if (uart_data->idx < uart_data->len) {
|
||||||
|
while ( (uart_data->regs->sr1 & MC9328MXL_UART_SR1_TRDY) &&
|
||||||
|
(uart_data->idx < uart_data->len)) {
|
||||||
|
uart_data->regs->txd = uart_data->buf[uart_data->idx];
|
||||||
|
uart_data->idx++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
len = uart_data->len;
|
||||||
|
uart_data->len = 0;
|
||||||
|
imx_uart_data[minor].regs->cr1 &= ~MC9328MXL_UART_CR1_TXMPTYEN;
|
||||||
|
rtems_termios_dequeue_characters(uart_data->tty, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the UART's baud rate. The calculation is:
|
||||||
|
* (baud * 16) / ref_freq = num/demom
|
||||||
|
*
|
||||||
|
* ref_freq = perclk1 / RFDIV[2:0]
|
||||||
|
* BIR = num - 1
|
||||||
|
* BMR = demom - 1
|
||||||
|
*
|
||||||
|
* Setting 'num' to 16 yields this equation:
|
||||||
|
* demom = ref_freq / baud
|
||||||
|
*/
|
||||||
|
static void imx_uart_set_baud(int minor, int baud)
|
||||||
|
{
|
||||||
|
unsigned int perclk1;
|
||||||
|
unsigned int denom;
|
||||||
|
unsigned int ref_freq = 0;
|
||||||
|
uint32_t fcr;
|
||||||
|
|
||||||
|
perclk1 = get_perclk1_freq();
|
||||||
|
fcr = imx_uart_data[minor].regs->fcr;
|
||||||
|
|
||||||
|
switch(fcr & MC9328MXL_UART_FCR_RFDIV_MASK) {
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_1: ref_freq = perclk1/1; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_2: ref_freq = perclk1/2; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_3: ref_freq = perclk1/3; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_4: ref_freq = perclk1/4; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_5: ref_freq = perclk1/5; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_6: ref_freq = perclk1/6; break;
|
||||||
|
case MC9328MXL_UART_FCR_RFDIV_7: ref_freq = perclk1/7; break;
|
||||||
|
default:
|
||||||
|
rtems_panic("%s:%d Unknown RFDIV: 0x%x",
|
||||||
|
__FUNCTION__, __LINE__,
|
||||||
|
fcr & MC9328MXL_UART_FCR_RFDIV_MASK);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
denom = ref_freq / baud;
|
||||||
|
|
||||||
|
imx_uart_data[minor].regs->bir = 0xf;
|
||||||
|
imx_uart_data[minor].regs->bmr = denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polled, non-blocking read from UART
|
||||||
|
*/
|
||||||
|
int imx_uart_poll_read_char(int minor)
|
||||||
|
{
|
||||||
|
return imx_uart_poll_read(minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polled, blocking write from UART
|
||||||
|
*/
|
||||||
|
void imx_uart_poll_write_char(int minor, char c)
|
||||||
|
{
|
||||||
|
imx_uart_poll_write(minor, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions for printk() and friends.
|
||||||
|
*/
|
||||||
|
void _BSP_output_char(char c)
|
||||||
|
{
|
||||||
|
poll_write(c);
|
||||||
|
if (c == '\n') {
|
||||||
|
poll_write('\r');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BSP_output_char_function_type BSP_output_char = _BSP_output_char;
|
||||||
|
|
||||||
|
|
||||||
|
char _BSP_poll_char()
|
||||||
|
{
|
||||||
|
return poll_read();
|
||||||
|
}
|
||||||
|
BSP_polling_getchar_function_type BSP_poll_char = _BSP_poll_char;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ void bsp_cleanup(void)
|
|||||||
*/
|
*/
|
||||||
printk("\n");
|
printk("\n");
|
||||||
printk(line);
|
printk(line);
|
||||||
while (uart_poll_read(0) < 0) continue;
|
while (BSP_poll_char() < 0) continue;
|
||||||
|
|
||||||
bsp_reset();
|
bsp_reset();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user