forked from Imagelibrary/rtems
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
This commit is contained in:
835
bsps/powerpc/gen5200/console/console.c
Normal file
835
bsps/powerpc/gen5200/console/console.c
Normal file
@@ -0,0 +1,835 @@
|
||||
/*===============================================================*\
|
||||
| Project: RTEMS generic MPC5200 BSP |
|
||||
+-----------------------------------------------------------------+
|
||||
| Partially based on the code references which are named below. |
|
||||
| Adaptions, modifications, enhancements and any recent parts of |
|
||||
| the code are: |
|
||||
| Copyright (c) 2005 |
|
||||
| Embedded Brains GmbH |
|
||||
| Obere Lagerstr. 30 |
|
||||
| D-82178 Puchheim |
|
||||
| Germany |
|
||||
| rtems@embedded-brains.de |
|
||||
+-----------------------------------------------------------------+
|
||||
| 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. |
|
||||
| |
|
||||
+-----------------------------------------------------------------+
|
||||
| this file contains the console driver functions |
|
||||
\*===============================================================*/
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* Module: console.c */
|
||||
/* Date: 07/17/2003 */
|
||||
/* Purpose: RTEMS MPC5x00 console driver */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Description: */
|
||||
/* */
|
||||
/* The PSCs of mpc5200 are assigned as follows */
|
||||
/* */
|
||||
/* Channel Device Minor Note */
|
||||
/* PSC1 /dev/tty0 0 */
|
||||
/* PSC2 /dev/tty1 1 */
|
||||
/* PSC3 /dev/tty2 2 */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Code */
|
||||
/* References: Serial driver for MPC8260ads */
|
||||
/* Module: console-generic.c */
|
||||
/* Project: RTEMS 4.6.0pre1 / MPC8260ads BSP */
|
||||
/* Version 1.3 */
|
||||
/* Date: 2002/11/04 */
|
||||
/* */
|
||||
/* Author(s) / Copyright(s): */
|
||||
/* */
|
||||
/* Author: Jay Monkman (jmonkman@frasca.com) */
|
||||
/* Copyright (C) 1998 by Frasca International, Inc. */
|
||||
/* */
|
||||
/* Derived from c/src/lib/libbsp/m68k/gen360/console/console.c */
|
||||
/* written by: */
|
||||
/* W. Eric Norum */
|
||||
/* Saskatchewan Accelerator Laboratory */
|
||||
/* University of Saskatchewan */
|
||||
/* Saskatoon, Saskatchewan, CANADA */
|
||||
/* eric@skatter.usask.ca */
|
||||
/* */
|
||||
/* COPYRIGHT (c) 1989-2008. */
|
||||
/* On-Line Applications Research Corporation (OAR). */
|
||||
/* */
|
||||
/* Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca> */
|
||||
/* and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca> */
|
||||
/* Copyright (c) 1999, National Research Council of Canada */
|
||||
/* */
|
||||
/* Modifications by Andy Dachs <a.dachs@sstl.co.uk> to add MPC8260 */
|
||||
/* support. */
|
||||
/* Copyright (c) 2001, Surrey Satellite Technology Ltd */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Partially based on the code references which are named above. */
|
||||
/* Adaptions, modifications, enhancements and any recent parts of */
|
||||
/* the code are under the right of */
|
||||
/* */
|
||||
/* IPR Engineering, Dachauer Straße 38, D-80335 München */
|
||||
/* Copyright(C) 2003 */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* IPR Engineering makes no representation or warranties with */
|
||||
/* respect to the performance of this computer program, and */
|
||||
/* specifically disclaims any responsibility for any damages, */
|
||||
/* special or consequential, connected with the use of this program. */
|
||||
/* */
|
||||
/*---------------------------------------------------------------------*/
|
||||
/* */
|
||||
/* Version history: 1.0 */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <rtems.h>
|
||||
#include <bsp/mpc5200.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
|
||||
|
||||
#define NUM_PORTS MPC5200_PSC_NO
|
||||
|
||||
#define PSC1_MINOR 0
|
||||
#define PSC2_MINOR 1
|
||||
#define PSC3_MINOR 2
|
||||
#define PSC4_MINOR 3
|
||||
#define PSC5_MINOR 4
|
||||
#define PSC6_MINOR 5
|
||||
|
||||
uint32_t mpc5200_uart_avail_mask = BSP_UART_AVAIL_MASK;
|
||||
|
||||
#if defined(UARTS_USE_TERMIOS_INT)
|
||||
uint8_t psc_minor_to_irqname[NUM_PORTS] = {
|
||||
BSP_SIU_IRQ_PSC1,
|
||||
BSP_SIU_IRQ_PSC2,
|
||||
BSP_SIU_IRQ_PSC3,
|
||||
BSP_SIU_IRQ_PSC4,
|
||||
BSP_SIU_IRQ_PSC5,
|
||||
BSP_SIU_IRQ_PSC6
|
||||
};
|
||||
|
||||
static int mpc5200_psc_irqname_to_minor(int name) {
|
||||
int minor;
|
||||
uint8_t *chrptr;
|
||||
|
||||
chrptr = memchr(psc_minor_to_irqname, name, sizeof(psc_minor_to_irqname));
|
||||
if (chrptr != NULL) {
|
||||
minor = chrptr - psc_minor_to_irqname;
|
||||
} else {
|
||||
minor = -1;
|
||||
}
|
||||
return minor;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void A_BSP_output_char(char c);
|
||||
static int A_BSP_get_char(void);
|
||||
BSP_output_char_function_type BSP_output_char = A_BSP_output_char;
|
||||
|
||||
BSP_polling_getchar_function_type BSP_poll_char = A_BSP_get_char;
|
||||
|
||||
/* Used to handle premature outputs of printk */
|
||||
bool console_initialized = false;
|
||||
|
||||
/* per channel info structure */
|
||||
struct per_channel_info {
|
||||
uint16_t shadow_imr;
|
||||
uint8_t shadow_mode1;
|
||||
uint8_t shadow_mode2;
|
||||
int cur_tx_len;
|
||||
int rx_interrupts;
|
||||
int tx_interrupts;
|
||||
int rx_characters;
|
||||
int tx_characters;
|
||||
int breaks_detected;
|
||||
int framing_errors;
|
||||
int parity_errors;
|
||||
int overrun_errors;
|
||||
};
|
||||
|
||||
/* Used to handle more than one channel */
|
||||
struct per_channel_info channel_info[NUM_PORTS];
|
||||
|
||||
/*
|
||||
* XXX: there are only 6 PSCs, but PSC6 has an extra register gap
|
||||
* from PSC5, therefore we instantiate seven(!) PSC register sets
|
||||
*/
|
||||
uint8_t psc_minor_to_regset[MPC5200_PSC_NO] = {0,1,2,3,4,6};
|
||||
|
||||
/* Used to track termios private data for callbacks */
|
||||
struct rtems_termios_tty *ttyp[NUM_PORTS];
|
||||
|
||||
static int mpc5200_psc_setAttributes(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
int baud;
|
||||
uint8_t csize=0, cstopb, parenb, parodd;
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
/* Baud rate */
|
||||
baud = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
if (baud > 0) {
|
||||
/*
|
||||
* Calculate baud rate
|
||||
* round divider to nearest!
|
||||
*/
|
||||
baud = (IPB_CLOCK + baud *16) / (baud * 32);
|
||||
}
|
||||
|
||||
/* Number of data bits */
|
||||
switch ( t->c_cflag & CSIZE ) {
|
||||
case CS5: csize = 0x00; break;
|
||||
case CS6: csize = 0x01; break;
|
||||
case CS7: csize = 0x02; break;
|
||||
case CS8: csize = 0x03; break;
|
||||
}
|
||||
|
||||
/* Stop bits */
|
||||
if(csize == 0) {
|
||||
if(t->c_cflag & CSTOPB)
|
||||
cstopb = 0x0F; /* Two stop bits */
|
||||
else
|
||||
cstopb = 0x00; /* One stop bit */
|
||||
} else {
|
||||
if(t->c_cflag & CSTOPB)
|
||||
cstopb = 0x0F; /* Two stop bits */
|
||||
else
|
||||
cstopb = 0x07; /* One stop bit */
|
||||
}
|
||||
|
||||
/* Parity */
|
||||
if (t->c_cflag & PARENB)
|
||||
parenb = 0x00; /* Parity enabled on Tx and Rx */
|
||||
else
|
||||
parenb = 0x10; /* No parity on Tx and Rx */
|
||||
|
||||
if (t->c_cflag & PARODD)
|
||||
parodd = 0x04; /* Odd parity */
|
||||
else
|
||||
parodd = 0x00;
|
||||
|
||||
/*
|
||||
* Set upper timer counter
|
||||
*/
|
||||
psc->ctur = (uint8_t) (baud >> 8);
|
||||
|
||||
/*
|
||||
* Set lower timer counter
|
||||
*/
|
||||
psc->ctlr = (uint8_t) baud;
|
||||
|
||||
/*
|
||||
* Reset mode pointer
|
||||
*/
|
||||
psc->cr = ((1 << 4) << 8);
|
||||
|
||||
/*
|
||||
* Set mode1 register
|
||||
*/
|
||||
channel_info[minor].shadow_mode1 &= ~(0x1F);
|
||||
psc->mr = channel_info[minor].shadow_mode1 | (csize | parenb | parodd);
|
||||
|
||||
/*
|
||||
* Set mode2 register
|
||||
*/
|
||||
channel_info[minor].shadow_mode2 &= ~(0x0F);
|
||||
psc->mr = channel_info[minor].shadow_mode2 | cstopb;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int mpc5200_uart_setAttributes(int minor, const struct termios *t)
|
||||
{
|
||||
/*
|
||||
* Check that port number is valid
|
||||
*/
|
||||
if( (minor < PSC1_MINOR) || (minor > NUM_PORTS-1) )
|
||||
return 0;
|
||||
|
||||
return mpc5200_psc_setAttributes(minor, t);
|
||||
|
||||
}
|
||||
|
||||
#ifdef UARTS_USE_TERMIOS_INT
|
||||
/*
|
||||
* Interrupt handlers
|
||||
*/
|
||||
static void mpc5200_psc_interrupt_handler(rtems_irq_hdl_param handle)
|
||||
{
|
||||
unsigned char c;
|
||||
uint16_t isr;
|
||||
int minor = (int)handle;
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
/*
|
||||
* get content of psc interrupt status
|
||||
*/
|
||||
isr = psc->isr_imr;
|
||||
|
||||
/*
|
||||
* Character received?
|
||||
*/
|
||||
if (isr & ISR_RX_RDY_FULL) {
|
||||
|
||||
channel_info[minor].rx_interrupts++;
|
||||
|
||||
|
||||
#ifndef SINGLE_CHAR_MODE
|
||||
while(psc->rfnum) {
|
||||
#endif
|
||||
/*
|
||||
* get the character
|
||||
*/
|
||||
c = (psc->rb_tb >> 24);
|
||||
|
||||
if (ttyp[minor] != NULL) {
|
||||
rtems_termios_enqueue_raw_characters(
|
||||
(void *)ttyp[minor], (char *)&c, (int)1);
|
||||
channel_info[minor].rx_characters++;
|
||||
}
|
||||
|
||||
#ifndef SINGLE_CHAR_MODE
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Character transmitted ?
|
||||
*/
|
||||
if (isr & ISR_TX_RDY & channel_info[minor].shadow_imr) {
|
||||
channel_info[minor].tx_interrupts++;
|
||||
|
||||
if (ttyp[minor] != NULL) {
|
||||
#ifndef SINGLE_CHAR_MODE
|
||||
rtems_termios_dequeue_characters(
|
||||
(void *)ttyp[minor], channel_info[minor].cur_tx_len);
|
||||
channel_info[minor].tx_characters += channel_info[minor].cur_tx_len;
|
||||
#else
|
||||
rtems_termios_dequeue_characters((void *)ttyp[minor], (int)1);
|
||||
channel_info[minor].tx_characters++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if(isr & ISR_ERROR) {
|
||||
if(isr & ISR_RB)
|
||||
channel_info[minor].breaks_detected++;
|
||||
if(isr & ISR_FE)
|
||||
channel_info[minor].framing_errors++;
|
||||
if(isr & ISR_PE)
|
||||
channel_info[minor].parity_errors++;
|
||||
if(isr & ISR_OE)
|
||||
channel_info[minor].overrun_errors++;
|
||||
|
||||
/*
|
||||
* Reset error status
|
||||
*/
|
||||
psc->cr = ((4 << 4) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
static void mpc5200_psc_enable(
|
||||
const rtems_irq_connect_data* ptr
|
||||
)
|
||||
{
|
||||
struct mpc5200_psc *psc;
|
||||
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
|
||||
|
||||
if (minor >= 0) {
|
||||
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
psc->isr_imr = channel_info[minor].shadow_imr |=
|
||||
(IMR_RX_RDY_FULL | IMR_TX_RDY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void mpc5200_psc_disable(
|
||||
const rtems_irq_connect_data* ptr
|
||||
)
|
||||
{
|
||||
struct mpc5200_psc *psc;
|
||||
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
|
||||
|
||||
if (minor >= 0) {
|
||||
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
psc->isr_imr = channel_info[minor].shadow_imr &=
|
||||
~(IMR_RX_RDY_FULL | IMR_TX_RDY);
|
||||
}
|
||||
}
|
||||
|
||||
static int mpc5200_psc_isOn(
|
||||
const rtems_irq_connect_data* ptr
|
||||
)
|
||||
{
|
||||
struct mpc5200_psc *psc;
|
||||
int minor = mpc5200_psc_irqname_to_minor(ptr->name);
|
||||
|
||||
if (minor >= 0) {
|
||||
psc = (struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
return ((psc->isr_imr & IMR_RX_RDY_FULL) & (psc->isr_imr & IMR_TX_RDY));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static rtems_irq_connect_data consoleIrqData;
|
||||
#endif
|
||||
|
||||
static void mpc5200_uart_psc_initialize(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
uint32_t baud_divider;
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
/*
|
||||
* Check that minor number is valid
|
||||
*/
|
||||
if ((minor < PSC1_MINOR) || (minor >= (PSC1_MINOR + NUM_PORTS)))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clear per channel info
|
||||
*/
|
||||
memset((void *)&channel_info[minor], 0, sizeof(struct per_channel_info));
|
||||
|
||||
/*
|
||||
* Reset receiver and transmitter
|
||||
*/
|
||||
psc->cr = ((2 << 4) << 8);
|
||||
psc->cr = ((3 << 4) << 8);
|
||||
|
||||
/*
|
||||
* Reset mode pointer
|
||||
*/
|
||||
psc->cr = ((1 << 4) << 8);
|
||||
|
||||
/*
|
||||
* Set clock select register
|
||||
*/
|
||||
psc->sr_csr = 0;
|
||||
|
||||
/*
|
||||
* Set mode1 register
|
||||
*/
|
||||
psc->mr = channel_info[minor].shadow_mode1 = 0x33; /* 8Bit / no parity */
|
||||
|
||||
/*
|
||||
* Set mode2 register
|
||||
*/
|
||||
psc->mr = channel_info[minor].shadow_mode2 = 7; /* 1 stop bit */
|
||||
|
||||
/*
|
||||
* Set rx FIFO alarm
|
||||
*/
|
||||
psc->rfalarm = RX_FIFO_SIZE - 1;
|
||||
|
||||
/*
|
||||
* Set tx FIFO alarm
|
||||
*/
|
||||
psc->tfalarm = 1;
|
||||
|
||||
baud_divider =
|
||||
(IPB_CLOCK + GEN5200_CONSOLE_BAUD *16) / (GEN5200_CONSOLE_BAUD * 32);
|
||||
|
||||
/*
|
||||
* Set upper timer counter
|
||||
*/
|
||||
psc->ctur = baud_divider >> 16;
|
||||
|
||||
/*
|
||||
* Set lower timer counter
|
||||
*/
|
||||
|
||||
psc->ctlr = baud_divider & 0x0000ffff;
|
||||
|
||||
/*
|
||||
* Disable Frame mode / set granularity 0
|
||||
*/
|
||||
psc->tfcntl = 0;
|
||||
|
||||
#ifdef UARTS_USE_TERMIOS_INT
|
||||
/*
|
||||
* Tie interrupt dependent routines
|
||||
*/
|
||||
consoleIrqData.on = mpc5200_psc_enable;
|
||||
consoleIrqData.off = mpc5200_psc_disable;
|
||||
consoleIrqData.isOn = mpc5200_psc_isOn;
|
||||
consoleIrqData.handle = (rtems_irq_hdl_param)minor;
|
||||
consoleIrqData.hdl = (rtems_irq_hdl)mpc5200_psc_interrupt_handler;
|
||||
|
||||
/*
|
||||
* Tie interrupt handler
|
||||
*/
|
||||
consoleIrqData.name = psc_minor_to_irqname[minor];
|
||||
|
||||
/*
|
||||
* Install rtems irq handler
|
||||
*/
|
||||
assert(BSP_install_rtems_irq_handler(&consoleIrqData) == 1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reset rx fifo errors Error/UF/OF
|
||||
*/
|
||||
psc->rfstat |= 0x70;
|
||||
|
||||
/*
|
||||
* Reset tx fifo errors Error/UF/OF
|
||||
*/
|
||||
psc->tfstat |= 0x70;
|
||||
|
||||
#ifdef UARTS_USE_TERMIOS_INT
|
||||
/*
|
||||
* Unmask receive interrupt
|
||||
*/
|
||||
psc->isr_imr = channel_info[minor].shadow_imr = IMR_RX_RDY_FULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enable receiver
|
||||
*/
|
||||
psc->cr = ((1 << 0) << 8);
|
||||
|
||||
/*
|
||||
* Enable transmitter
|
||||
*/
|
||||
psc->cr = ((1 << 2) << 8);
|
||||
}
|
||||
|
||||
|
||||
static int mpc5200_uart_pollRead(
|
||||
int minor
|
||||
)
|
||||
{
|
||||
unsigned char c;
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
if (psc->sr_csr & (1 << 8))
|
||||
c = (psc->rb_tb >> 24);
|
||||
else
|
||||
return -1;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t mpc5200_uart_pollWrite(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
size_t retval = len;
|
||||
const char *tmp_buf = buf;
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
while(len--) {
|
||||
while(!(psc->sr_csr & (1 << 11)))
|
||||
continue;
|
||||
|
||||
/*rtems_cache_flush_multiple_data_lines( (void *)buf, 1);*/
|
||||
|
||||
psc->rb_tb = (*tmp_buf << 24);
|
||||
|
||||
tmp_buf++;
|
||||
|
||||
}
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
static ssize_t mpc5200_uart_write(
|
||||
int minor,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
struct mpc5200_psc *psc =
|
||||
(struct mpc5200_psc *)(&mpc5200.psc[psc_minor_to_regset[minor]]);
|
||||
|
||||
if (len > 0) {
|
||||
int frame_len = len;
|
||||
const char *frame_buf = buf;
|
||||
|
||||
/*
|
||||
* Check tx fifo space
|
||||
*/
|
||||
if(len > (TX_FIFO_SIZE - psc->tfnum))
|
||||
frame_len = TX_FIFO_SIZE - psc->tfnum;
|
||||
|
||||
#ifndef SINGLE_CHAR_MODE
|
||||
channel_info[minor].cur_tx_len = frame_len;
|
||||
#else
|
||||
frame_len = 1;
|
||||
#endif
|
||||
|
||||
/*rtems_cache_flush_multiple_data_lines( (void *)frame_buf, frame_len);*/
|
||||
|
||||
while (frame_len--)
|
||||
/* perform byte write to avoid extra NUL characters */
|
||||
(* (volatile char *)&(psc->rb_tb)) = *frame_buf++;
|
||||
|
||||
/*
|
||||
* unmask interrupt
|
||||
*/
|
||||
psc->isr_imr = channel_info[minor].shadow_imr |= IMR_TX_RDY;
|
||||
} else {
|
||||
/*
|
||||
* mask interrupt
|
||||
*/
|
||||
psc->isr_imr = channel_info[minor].shadow_imr &= ~(IMR_TX_RDY);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print functions prototyped in bspIo.h
|
||||
*/
|
||||
static void A_BSP_output_char(
|
||||
char c
|
||||
)
|
||||
{
|
||||
/*
|
||||
* If we are using U-Boot, then the console is already initialized
|
||||
* and we can just poll bytes out at any time.
|
||||
*/
|
||||
#if !defined(HAS_UBOOT)
|
||||
if (console_initialized == false)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#define PRINTK_WRITE mpc5200_uart_pollWrite
|
||||
|
||||
PRINTK_WRITE(PRINTK_MINOR, &c, 1 );
|
||||
}
|
||||
|
||||
static int A_BSP_get_char(void)
|
||||
{
|
||||
/*
|
||||
* If we are using U-Boot, then the console is already initialized
|
||||
* and we can just poll bytes in at any time.
|
||||
*/
|
||||
#if !defined(HAS_UBOOT)
|
||||
if (console_initialized == false)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
return mpc5200_uart_pollRead(0);
|
||||
}
|
||||
|
||||
/*
|
||||
***************
|
||||
* BOILERPLATE *
|
||||
***************
|
||||
*
|
||||
* All these functions are prototyped in rtems/c/src/lib/include/console.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize and register the device
|
||||
*/
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code status;
|
||||
rtems_device_minor_number console_minor;
|
||||
char dev_name[] = "/dev/ttyx";
|
||||
uint32_t tty_num = 0;
|
||||
bool first = true;
|
||||
|
||||
/*
|
||||
* Always use and set up TERMIOS
|
||||
*/
|
||||
console_minor = PSC1_MINOR;
|
||||
rtems_termios_initialize();
|
||||
|
||||
for (console_minor = PSC1_MINOR;
|
||||
console_minor < PSC1_MINOR + NUM_PORTS;
|
||||
console_minor++) {
|
||||
/*
|
||||
* check, whether UART is available for this board
|
||||
*/
|
||||
if (0 != ((1 << console_minor) & (mpc5200_uart_avail_mask))) {
|
||||
/*
|
||||
* Do device-specific initialization and registration for Motorola IceCube
|
||||
*/
|
||||
mpc5200_uart_psc_initialize(console_minor); /* /dev/tty0 */
|
||||
dev_name[8] = '0' + tty_num;
|
||||
status = rtems_io_register_name (dev_name, major, console_minor);
|
||||
assert(status == RTEMS_SUCCESSFUL);
|
||||
|
||||
#ifdef MPC5200_PSC_INDEX_FOR_GPS_MODULE
|
||||
if (console_minor == MPC5200_PSC_INDEX_FOR_GPS_MODULE) {
|
||||
status = rtems_io_register_name("/dev/gps", major, console_minor);
|
||||
assert(status == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
|
||||
/* Now register the RTEMS console */
|
||||
status = rtems_io_register_name ("/dev/console", major, console_minor);
|
||||
assert(status == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
tty_num++;
|
||||
}
|
||||
}
|
||||
|
||||
console_initialized = true;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the device
|
||||
*/
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
rtems_status_code sc;
|
||||
|
||||
#ifdef UARTS_USE_TERMIOS_INT
|
||||
static const rtems_termios_callbacks intrCallbacks = {
|
||||
NULL, /* firstOpen */
|
||||
NULL, /* lastClose */
|
||||
NULL, /* pollRead */
|
||||
mpc5200_uart_write, /* write */
|
||||
mpc5200_uart_setAttributes, /* setAttributes */
|
||||
NULL,
|
||||
NULL,
|
||||
1 /* outputUsesInterrupts */
|
||||
};
|
||||
#else
|
||||
static const rtems_termios_callbacks pollCallbacks = {
|
||||
NULL, /* firstOpen */
|
||||
NULL, /* lastClose */
|
||||
mpc5200_uart_pollRead, /* pollRead */
|
||||
mpc5200_uart_pollWrite, /* write */
|
||||
mpc5200_uart_setAttributes, /* setAttributes */
|
||||
NULL,
|
||||
NULL,
|
||||
0 /* output don't use Interrupts */
|
||||
};
|
||||
#endif
|
||||
|
||||
if(minor > NUM_PORTS - 1)
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#ifdef UARTS_USE_TERMIOS_INT
|
||||
sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
|
||||
#else /* RTEMS polled I/O with termios */
|
||||
sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
|
||||
#endif
|
||||
|
||||
ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */
|
||||
|
||||
if ( !sc )
|
||||
rtems_termios_set_initial_baud( ttyp[minor], GEN5200_CONSOLE_BAUD );
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close the device
|
||||
*/
|
||||
rtems_device_driver console_close(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
ttyp[minor] = NULL; /* mark for int handler: tty no longer open */
|
||||
|
||||
return rtems_termios_close( arg );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read from the device
|
||||
*/
|
||||
rtems_device_driver console_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if(minor > NUM_PORTS-1)
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
return rtems_termios_read(arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the device
|
||||
*/
|
||||
rtems_device_driver console_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
return rtems_termios_write(arg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle ioctl request.
|
||||
*/
|
||||
rtems_device_driver console_control(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
return rtems_termios_ioctl(arg);
|
||||
}
|
||||
107
bsps/powerpc/gen83xx/console/console-config.c
Normal file
107
bsps/powerpc/gen83xx/console/console-config.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Console configuration.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/bspIo.h>
|
||||
|
||||
#include <libchip/ns16550.h>
|
||||
|
||||
#include <mpc83xx/mpc83xx.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/console-termios.h>
|
||||
|
||||
#ifdef BSP_USE_UART_INTERRUPTS
|
||||
#define DEVICE_FNS &ns16550_handler_interrupt
|
||||
#else
|
||||
#define DEVICE_FNS &ns16550_handler_polled
|
||||
#endif
|
||||
|
||||
static uint8_t gen83xx_console_get_register(uintptr_t addr, uint8_t i)
|
||||
{
|
||||
volatile uint8_t *reg = (volatile uint8_t *) addr;
|
||||
|
||||
return reg [i];
|
||||
}
|
||||
|
||||
static void gen83xx_console_set_register(uintptr_t addr, uint8_t i, uint8_t val)
|
||||
{
|
||||
volatile uint8_t *reg = (volatile uint8_t *) addr;
|
||||
|
||||
reg [i] = val;
|
||||
}
|
||||
|
||||
static ns16550_context gen83xx_uart_context_0 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"),
|
||||
.get_reg = gen83xx_console_get_register,
|
||||
.set_reg = gen83xx_console_set_register,
|
||||
.port = (uintptr_t) &mpc83xx.duart[0],
|
||||
#if MPC83XX_CHIP_TYPE / 10 == 830
|
||||
.irq = BSP_IPIC_IRQ_UART,
|
||||
#else
|
||||
.irq = BSP_IPIC_IRQ_UART1,
|
||||
#endif
|
||||
.initial_baud = BSP_CONSOLE_BAUD
|
||||
};
|
||||
|
||||
#ifdef BSP_USE_UART2
|
||||
static ns16550_context gen83xx_uart_context_1 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"),
|
||||
.get_reg = gen83xx_console_get_register,
|
||||
.set_reg = gen83xx_console_set_register,
|
||||
.port = (uintptr_t) &mpc83xx.duart[1],
|
||||
#if MPC83XX_CHIP_TYPE / 10 == 830
|
||||
.irq = BSP_IPIC_IRQ_UART,
|
||||
#else
|
||||
.irq = BSP_IPIC_IRQ_UART2,
|
||||
#endif
|
||||
.initial_baud = BSP_CONSOLE_BAUD
|
||||
};
|
||||
#endif
|
||||
|
||||
const console_device console_device_table[] = {
|
||||
{
|
||||
.device_file = "/dev/ttyS0",
|
||||
.probe = ns16550_probe,
|
||||
.handler = DEVICE_FNS,
|
||||
.context = &gen83xx_uart_context_0.base
|
||||
}
|
||||
#ifdef BSP_USE_UART2
|
||||
, {
|
||||
.device_file = "/dev/ttyS1",
|
||||
.probe = ns16550_probe,
|
||||
.handler = DEVICE_FNS,
|
||||
.context = &gen83xx_uart_context_1.base
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table);
|
||||
|
||||
static void gen83xx_output_char(char c)
|
||||
{
|
||||
rtems_termios_device_context *ctx = console_device_table[0].context;
|
||||
|
||||
ns16550_polled_putchar(ctx, c);
|
||||
}
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = gen83xx_output_char;
|
||||
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
41
bsps/powerpc/mpc55xxevb/console/console-config.c
Normal file
41
bsps/powerpc/mpc55xxevb/console/console-config.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2012 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <bsp.h>
|
||||
#include <bsp/console-generic.h>
|
||||
#include <bsp/console-esci.h>
|
||||
#include <bsp/console-linflex.h>
|
||||
|
||||
CONSOLE_GENERIC_INFO_TABLE = {
|
||||
#ifdef MPC55XX_HAS_ESCI
|
||||
CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 0, &mpc55xx_esci_callbacks, "/dev/ttyS0")
|
||||
#ifdef ESCI_B
|
||||
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 1, &mpc55xx_esci_callbacks, "/dev/ttyS1")
|
||||
#endif
|
||||
#ifdef ESCI_C
|
||||
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 2, &mpc55xx_esci_callbacks, "/dev/ttyS2")
|
||||
#endif
|
||||
#ifdef ESCI_D
|
||||
, CONSOLE_GENERIC_INFO(mpc55xx_esci_devices + 3, &mpc55xx_esci_callbacks, "/dev/ttyS3")
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MPC55XX_HAS_LINFLEX
|
||||
CONSOLE_GENERIC_INFO(mpc55xx_linflex_devices + 0, &mpc55xx_linflex_callbacks, "/dev/ttyS0"),
|
||||
CONSOLE_GENERIC_INFO(mpc55xx_linflex_devices + 1, &mpc55xx_linflex_callbacks, "/dev/ttyS1")
|
||||
#endif
|
||||
};
|
||||
|
||||
CONSOLE_GENERIC_INFO_COUNT;
|
||||
|
||||
CONSOLE_GENERIC_MINOR(MPC55XX_CONSOLE_MINOR);
|
||||
354
bsps/powerpc/mpc55xxevb/console/console-esci.c
Normal file
354
bsps/powerpc/mpc55xxevb/console/console-esci.c
Normal file
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Console ESCI implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <bsp/console-esci.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#ifdef MPC55XX_HAS_ESCI
|
||||
|
||||
mpc55xx_esci_context mpc55xx_esci_devices [] = {
|
||||
{
|
||||
.regs = &ESCI_A,
|
||||
.irq = MPC55XX_IRQ_ESCI(0)
|
||||
}
|
||||
#ifdef ESCI_B
|
||||
, {
|
||||
.regs = &ESCI_B,
|
||||
.irq = MPC55XX_IRQ_ESCI(1)
|
||||
}
|
||||
#endif
|
||||
#ifdef ESCI_C
|
||||
, {
|
||||
.regs = &ESCI_C,
|
||||
.irq = MPC55XX_IRQ_ESCI(2)
|
||||
}
|
||||
#endif
|
||||
#ifdef ESCI_D
|
||||
, {
|
||||
.regs = &ESCI_D,
|
||||
.irq = MPC55XX_IRQ_ESCI(3)
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
static void mpc55xx_esci_poll_write(int minor, char c)
|
||||
{
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
const union ESCI_SR_tag clear_tdre = { .B = { .TDRE = 1 } };
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
rtems_interrupt_level level;
|
||||
bool done = false;
|
||||
bool wait_for_transmit_done = false;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
if (self->transmit_nest_level == 0) {
|
||||
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
|
||||
|
||||
if (cr1.B.TIE != 0) {
|
||||
cr1.B.TIE = 0;
|
||||
regs->CR1.R = cr1.R;
|
||||
wait_for_transmit_done = !self->transmit_in_progress;
|
||||
self->transmit_nest_level = 1;
|
||||
}
|
||||
} else {
|
||||
++self->transmit_nest_level;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
while (!done) {
|
||||
rtems_interrupt_disable(level);
|
||||
bool tx = self->transmit_in_progress;
|
||||
if (!tx || (tx && regs->SR.B.TDRE)) {
|
||||
regs->SR.R = clear_tdre.R;
|
||||
regs->DR.B.D = c;
|
||||
self->transmit_in_progress = true;
|
||||
done = true;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
done = false;
|
||||
while (!done) {
|
||||
rtems_interrupt_disable(level);
|
||||
if (wait_for_transmit_done) {
|
||||
if (regs->SR.B.TDRE) {
|
||||
regs->SR.R = clear_tdre.R;
|
||||
self->transmit_in_progress = false;
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (done && self->transmit_nest_level > 0) {
|
||||
--self->transmit_nest_level;
|
||||
|
||||
if (self->transmit_nest_level == 0) {
|
||||
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
|
||||
|
||||
cr1.B.TIE = 1;
|
||||
regs->CR1.R = cr1.R;
|
||||
}
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mpc55xx_esci_interrupts_clear_and_enable(
|
||||
mpc55xx_esci_context *self
|
||||
)
|
||||
{
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
cr1.R = regs->CR1.R;
|
||||
cr1.B.RIE = 1;
|
||||
cr1.B.TIE = 1;
|
||||
regs->CR1.R = cr1.R;
|
||||
regs->SR.R = regs->SR.R;
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
static inline void mpc55xx_esci_interrupts_disable(mpc55xx_esci_context *self)
|
||||
{
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
cr1.R = regs->CR1.R;
|
||||
cr1.B.RIE = 0;
|
||||
cr1.B.TIE = 0;
|
||||
regs->CR1.R = cr1.R;
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
static void mpc55xx_esci_interrupt_handler(void *arg)
|
||||
{
|
||||
mpc55xx_esci_context *self = arg;
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
|
||||
union ESCI_SR_tag active = MPC55XX_ZERO_FLAGS;
|
||||
rtems_interrupt_level level;
|
||||
|
||||
/* Status */
|
||||
sr.R = regs->SR.R;
|
||||
|
||||
/* Receive data register full? */
|
||||
if (sr.B.RDRF != 0) {
|
||||
active.B.RDRF = 1;
|
||||
}
|
||||
|
||||
/* Transmit data register empty? */
|
||||
if (sr.B.TDRE != 0) {
|
||||
active.B.TDRE = 1;
|
||||
}
|
||||
|
||||
/* Clear flags */
|
||||
rtems_interrupt_disable(level);
|
||||
regs->SR.R = active.R;
|
||||
self->transmit_in_progress = false;
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
/* Enqueue */
|
||||
if (active.B.RDRF != 0) {
|
||||
char c = regs->DR.B.D;
|
||||
rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
|
||||
}
|
||||
|
||||
/* Dequeue */
|
||||
if (active.B.TDRE != 0) {
|
||||
rtems_termios_dequeue_characters(self->tty, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int mpc55xx_esci_set_attributes(int minor, const struct termios *t)
|
||||
{
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
union ESCI_CR1_tag cr1 = { .R = regs->CR1.R };
|
||||
union ESCI_CR2_tag cr2 = MPC55XX_ZERO_FLAGS;
|
||||
rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
|
||||
/* Enable module */
|
||||
cr2.B.MDIS = 0;
|
||||
|
||||
/* Interrupts */
|
||||
cr1.B.TCIE = 0;
|
||||
cr1.B.ILIE = 0;
|
||||
cr2.B.IEBERR = 0;
|
||||
cr2.B.ORIE = 0;
|
||||
cr2.B.NFIE = 0;
|
||||
cr2.B.FEIE = 0;
|
||||
cr2.B.PFIE = 0;
|
||||
|
||||
/* Disable receiver wake-up standby */
|
||||
cr1.B.RWU = 0;
|
||||
|
||||
/* Disable DMA channels */
|
||||
cr2.B.RXDMA = 0;
|
||||
cr2.B.TXDMA = 0;
|
||||
|
||||
/* Idle line type */
|
||||
cr1.B.ILT = 0;
|
||||
|
||||
/* Disable loops */
|
||||
cr1.B.LOOPS = 0;
|
||||
|
||||
/* Enable or disable receiver */
|
||||
cr1.B.RE = (t->c_cflag & CREAD) ? 1 : 0;
|
||||
|
||||
/* Enable transmitter */
|
||||
cr1.B.TE = 1;
|
||||
|
||||
/* Baud rate */
|
||||
if (br > 0) {
|
||||
br = bsp_clock_speed / (16 * br);
|
||||
br = (br > 8191) ? 8191 : br;
|
||||
} else {
|
||||
br = 0;
|
||||
}
|
||||
cr1.B.SBR = br;
|
||||
|
||||
/* Number of data bits */
|
||||
if ((t->c_cflag & CSIZE) != CS8) {
|
||||
return -1;
|
||||
}
|
||||
cr1.B.M = 0;
|
||||
|
||||
/* Parity */
|
||||
cr1.B.PE = (t->c_cflag & PARENB) ? 1 : 0;
|
||||
cr1.B.PT = (t->c_cflag & PARODD) ? 1 : 0;
|
||||
|
||||
/* Stop bits */
|
||||
if (t->c_cflag & CSTOPB ) {
|
||||
/* Two stop bits */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disable LIN */
|
||||
regs->LCR.R = 0;
|
||||
|
||||
/* Set control registers */
|
||||
regs->CR2.R = cr2.R;
|
||||
regs->CR1.R = cr1.R;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_esci_first_open(int major, int minor, void *arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
int rv = 0;
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
|
||||
|
||||
self->tty = tty;
|
||||
|
||||
rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
|
||||
if (rv != 0) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_BAUD);
|
||||
}
|
||||
|
||||
rv = mpc55xx_esci_set_attributes(minor, &tty->termios);
|
||||
if (rv != 0) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_ATTRIBUTES);
|
||||
}
|
||||
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
self->irq,
|
||||
"eSCI",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
MPC55XX_INTC_DEFAULT_PRIORITY,
|
||||
mpc55xx_esci_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_ESCI_IRQ_INSTALL);
|
||||
}
|
||||
|
||||
mpc55xx_esci_interrupts_clear_and_enable(self);
|
||||
self->transmit_in_progress = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_esci_last_close(int major, int minor, void* arg)
|
||||
{
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
|
||||
mpc55xx_esci_interrupts_disable(self);
|
||||
self->tty = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_esci_poll_read(int minor)
|
||||
{
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
volatile struct ESCI_tag *regs = self->regs;
|
||||
union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS;
|
||||
rtems_interrupt_level level;
|
||||
int c = -1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
if (regs->SR.B.RDRF != 0) {
|
||||
/* Clear flag */
|
||||
sr.B.RDRF = 1;
|
||||
regs->SR.R = sr.R;
|
||||
|
||||
/* Read */
|
||||
c = regs->DR.B.D;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int mpc55xx_esci_write(int minor, const char *out, size_t n)
|
||||
{
|
||||
if (n > 0) {
|
||||
mpc55xx_esci_context *self = console_generic_get_context(minor);
|
||||
|
||||
self->regs->DR.B.D = out [0];
|
||||
self->transmit_in_progress = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const console_generic_callbacks mpc55xx_esci_callbacks = {
|
||||
.termios_callbacks = {
|
||||
.firstOpen = mpc55xx_esci_first_open,
|
||||
.lastClose = mpc55xx_esci_last_close,
|
||||
.write = mpc55xx_esci_write,
|
||||
.setAttributes = mpc55xx_esci_set_attributes,
|
||||
.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
|
||||
},
|
||||
.poll_read = mpc55xx_esci_poll_read,
|
||||
.poll_write = mpc55xx_esci_poll_write
|
||||
};
|
||||
|
||||
#endif /* MPC55XX_HAS_ESCI */
|
||||
168
bsps/powerpc/mpc55xxevb/console/console-generic.c
Normal file
168
bsps/powerpc/mpc55xxevb/console/console-generic.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Generic console driver implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <sys/cdefs.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/console-generic.h>
|
||||
#include <bsp/fatal.h>
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/console.h>
|
||||
|
||||
static const struct termios console_generic_termios = {
|
||||
.c_cflag = CS8 | CREAD | CLOCAL | __CONCAT(B, BSP_DEFAULT_BAUD_RATE)
|
||||
};
|
||||
|
||||
static void console_generic_char_out(char c)
|
||||
{
|
||||
int minor = (int) console_generic_minor;
|
||||
const console_generic_callbacks *cb =
|
||||
console_generic_info_table [minor].callbacks;
|
||||
|
||||
(*cb->poll_write)(minor, c);
|
||||
}
|
||||
|
||||
static int console_generic_char_in(void)
|
||||
{
|
||||
int minor = (int) console_generic_minor;
|
||||
const console_generic_callbacks *cb =
|
||||
console_generic_info_table [minor].callbacks;
|
||||
|
||||
return (*cb->poll_read)(minor);
|
||||
}
|
||||
|
||||
static void console_generic_char_out_do_init(void)
|
||||
{
|
||||
int minor = (int) console_generic_minor;
|
||||
const console_generic_callbacks *cb =
|
||||
console_generic_info_table [minor].callbacks;
|
||||
const struct termios *term = &console_generic_termios;
|
||||
|
||||
BSP_output_char = console_generic_char_out;
|
||||
(*cb->termios_callbacks.setAttributes)(minor, term);
|
||||
}
|
||||
|
||||
static void console_generic_char_out_init(char c)
|
||||
{
|
||||
console_generic_char_out_do_init();
|
||||
console_generic_char_out(c);
|
||||
}
|
||||
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
const console_generic_info *info_table = console_generic_info_table;
|
||||
rtems_device_minor_number count = console_generic_info_count;
|
||||
rtems_device_minor_number console = console_generic_minor;
|
||||
|
||||
if (count <= 0) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_COUNT);
|
||||
}
|
||||
|
||||
rtems_termios_initialize();
|
||||
|
||||
for (minor = 0; minor < count; ++minor) {
|
||||
const console_generic_info *info = info_table + minor;
|
||||
|
||||
sc = rtems_io_register_name(info->device_path, major, minor);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_REGISTER);
|
||||
}
|
||||
}
|
||||
|
||||
sc = rtems_io_register_name(CONSOLE_DEVICE_NAME, major, console);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_GENERIC_REGISTER_CONSOLE);
|
||||
}
|
||||
|
||||
console_generic_char_out_do_init();
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
rtems_device_minor_number count = console_generic_info_count;
|
||||
|
||||
if (minor < count) {
|
||||
const console_generic_info *info = &console_generic_info_table [minor];
|
||||
|
||||
sc = rtems_termios_open(
|
||||
major,
|
||||
minor,
|
||||
arg,
|
||||
&info->callbacks->termios_callbacks
|
||||
);
|
||||
} else {
|
||||
sc = RTEMS_INVALID_ID;
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = console_generic_char_out_init;
|
||||
|
||||
BSP_polling_getchar_function_type BSP_poll_char = console_generic_char_in;
|
||||
417
bsps/powerpc/mpc55xxevb/console/console-linflex.c
Normal file
417
bsps/powerpc/mpc55xxevb/console/console-linflex.c
Normal file
@@ -0,0 +1,417 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @brief Console LINFlexD implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <bsp/console-linflex.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/fatal.h>
|
||||
#include <bsp/irq.h>
|
||||
|
||||
#ifdef MPC55XX_HAS_LINFLEX
|
||||
|
||||
mpc55xx_linflex_context mpc55xx_linflex_devices [] = {
|
||||
{
|
||||
.regs = &LINFLEX0,
|
||||
.irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(0),
|
||||
.irq_txi = MPC55XX_IRQ_LINFLEX_TXI(0),
|
||||
.irq_err = MPC55XX_IRQ_LINFLEX_ERR(0),
|
||||
.tx_pcr_register = &((SIU_tag *) &SIUL)->PCR18,
|
||||
.tx_pa_value = 1,
|
||||
.rx_pcr_register = &((SIU_tag *) &SIUL)->PCR19,
|
||||
.rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI31,
|
||||
.rx_padsel_value = 0
|
||||
}, {
|
||||
.regs = &LINFLEX1,
|
||||
.irq_rxi = MPC55XX_IRQ_LINFLEX_RXI(1),
|
||||
.irq_txi = MPC55XX_IRQ_LINFLEX_TXI(1),
|
||||
.irq_err = MPC55XX_IRQ_LINFLEX_ERR(1),
|
||||
.tx_pcr_register = &((SIU_tag *) &SIUL)->PCR94,
|
||||
.tx_pa_value = 1,
|
||||
.rx_pcr_register = &((SIU_tag *) &SIUL)->PCR95,
|
||||
.rx_psmi_register = &((SIU_tag *) &SIUL)->PSMI32,
|
||||
.rx_padsel_value = 2
|
||||
}
|
||||
};
|
||||
|
||||
static void enter_init_mode(volatile LINFLEX_tag *regs)
|
||||
{
|
||||
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
|
||||
cr1.B.SLEEP = 0;
|
||||
cr1.B.INIT = 1;
|
||||
regs->LINCR1.R = cr1.R;
|
||||
}
|
||||
|
||||
static void enter_active_mode(volatile LINFLEX_tag *regs)
|
||||
{
|
||||
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
|
||||
cr1.B.SLEEP = 0;
|
||||
cr1.B.INIT = 0;
|
||||
regs->LINCR1.R = cr1.R;
|
||||
}
|
||||
|
||||
static void enter_sleep_mode(volatile LINFLEX_tag *regs)
|
||||
{
|
||||
LINFLEX_LINCR1_32B_tag cr1 = { .R = regs->LINCR1.R };
|
||||
cr1.B.SLEEP = 1;
|
||||
cr1.B.INIT = 0;
|
||||
regs->LINCR1.R = cr1.R;
|
||||
}
|
||||
|
||||
static void mpc55xx_linflex_poll_write(int minor, char c)
|
||||
{
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
const LINFLEX_UARTSR_32B_tag clear_dtf = { .B = { .DTF_TFF = 1 } };
|
||||
rtems_interrupt_level level;
|
||||
bool done = false;
|
||||
bool wait_for_transmit_done = false;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
if (self->transmit_nest_level == 0) {
|
||||
LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
|
||||
|
||||
if (ier.B.DTIE != 0) {
|
||||
ier.B.DTIE = 0;
|
||||
regs->LINIER.R = ier.R;
|
||||
wait_for_transmit_done = !self->transmit_in_progress;
|
||||
self->transmit_nest_level = 1;
|
||||
}
|
||||
} else {
|
||||
++self->transmit_nest_level;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
while (!done) {
|
||||
rtems_interrupt_disable(level);
|
||||
bool tx = self->transmit_in_progress;
|
||||
if (!tx || (tx && regs->UARTSR.B.DTF_TFF)) {
|
||||
regs->UARTSR.R = clear_dtf.R;
|
||||
regs->BDRL.B.DATA0 = c;
|
||||
self->transmit_in_progress = true;
|
||||
done = true;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
|
||||
done = false;
|
||||
while (!done) {
|
||||
rtems_interrupt_disable(level);
|
||||
if (wait_for_transmit_done) {
|
||||
if (regs->UARTSR.B.DTF_TFF) {
|
||||
regs->UARTSR.R = clear_dtf.R;
|
||||
self->transmit_in_progress = false;
|
||||
done = true;
|
||||
}
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
|
||||
if (done && self->transmit_nest_level > 0) {
|
||||
--self->transmit_nest_level;
|
||||
|
||||
if (self->transmit_nest_level == 0) {
|
||||
LINFLEX_LINIER_32B_tag ier = { .R = regs->LINIER.R };
|
||||
|
||||
ier.B.DTIE = 1;
|
||||
regs->LINIER.R = ier.R;
|
||||
}
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
}
|
||||
}
|
||||
|
||||
static void mpc55xx_linflex_rx_interrupt_handler(void *arg)
|
||||
{
|
||||
mpc55xx_linflex_context *self = arg;
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
char c = regs->BDRM.B.DATA4;
|
||||
const LINFLEX_UARTSR_32B_tag clear_flags = { .B = { .RMB = 1, .DRF_RFE = 1 } };
|
||||
|
||||
regs->UARTSR.R = clear_flags.R;
|
||||
|
||||
rtems_termios_enqueue_raw_characters(self->tty, &c, 1);
|
||||
}
|
||||
|
||||
static void mpc55xx_linflex_tx_interrupt_handler(void *arg)
|
||||
{
|
||||
mpc55xx_linflex_context *self = arg;
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
|
||||
regs->UARTSR.B.DTF_TFF = 1; /* clear flag */
|
||||
self->transmit_in_progress = false;
|
||||
|
||||
rtems_termios_dequeue_characters(self->tty, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
static void mpc55xx_linflex_err_interrupt_handler(void *arg)
|
||||
{
|
||||
mpc55xx_linflex_context *self = arg;
|
||||
}
|
||||
*/
|
||||
|
||||
static int mpc55xx_linflex_set_attributes(int minor, const struct termios *t)
|
||||
{
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
LINFLEX_UARTCR_32B_tag uartcr = { .R = 0 };
|
||||
LINFLEX_GCR_32B_tag gcr = { .R = 0 };
|
||||
LINFLEX_LINIER_32B_tag ier = { .R = 0 };
|
||||
rtems_termios_baud_t br = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
LINFLEX_LINFBRR_32B_tag fbrr = { .R = 0 };
|
||||
LINFLEX_LINIBRR_32B_tag ibrr = { .R = 0 };
|
||||
|
||||
enter_init_mode(regs);
|
||||
|
||||
/* Set to UART-mode */
|
||||
uartcr.B.UART = 1;
|
||||
regs->UARTCR.R = uartcr.R;
|
||||
|
||||
/* Set to buffer mode with size 1 */
|
||||
uartcr.B.TDFL_TFC = 0;
|
||||
uartcr.B.RDFL_RFC0 = 0;
|
||||
uartcr.B.RFBM = 0;
|
||||
uartcr.B.TFBM = 0;
|
||||
|
||||
/* Enable receiver and transmitter */
|
||||
uartcr.B.RXEN = 1;
|
||||
uartcr.B.TXEN = 1;
|
||||
|
||||
/* Number of data bits */
|
||||
uartcr.B.WL1 = 0;
|
||||
if ((t->c_cflag & CSIZE) == CS8) {
|
||||
uartcr.B.WL0 = 1;
|
||||
} else if ((t->c_cflag & CSIZE) == CS7) {
|
||||
uartcr.B.WL0 = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parity */
|
||||
uartcr.B.PCE = (t->c_cflag & PARENB) ? 1 : 0;
|
||||
uartcr.B.PC1 = 0;
|
||||
uartcr.B.PC0 = (t->c_cflag & PARODD) ? 1 : 0;
|
||||
|
||||
/* Stop bits */
|
||||
gcr.B.STOP = (t->c_cflag & CSTOPB) ? 1 : 0;
|
||||
|
||||
/* Set control registers */
|
||||
regs->UARTCR.R = uartcr.R;
|
||||
regs->GCR.R = gcr.R;
|
||||
|
||||
/* Interrupts */
|
||||
ier.B.DTIE = 1;
|
||||
ier.B.DRIE = 1;
|
||||
regs->LINIER.R = ier.R;
|
||||
|
||||
/* Baud rate */
|
||||
if (br > 0) {
|
||||
uint32_t lfdiv_mult_32 = bsp_clock_speed * 2 / br;
|
||||
if((lfdiv_mult_32 & 0x1) != 0) {
|
||||
++lfdiv_mult_32;
|
||||
}
|
||||
fbrr.B.FBR = (lfdiv_mult_32 >> 1) & 0xF;
|
||||
ibrr.B.IBR = lfdiv_mult_32 >> 5;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
regs->LINFBRR.R = fbrr.R;
|
||||
regs->LINIBRR.R = ibrr.R;
|
||||
|
||||
enter_active_mode(regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_linflex_first_open(int major, int minor, void *arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
int rv = 0;
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
struct rtems_termios_tty *tty = console_generic_get_tty_at_open(arg);
|
||||
SIU_PCR_tag pcr = { .R = 0 };
|
||||
SIUL_PSMI_8B_tag psmi = { .R = 0 };
|
||||
|
||||
self->tty = tty;
|
||||
|
||||
pcr.B.IBE = 1;
|
||||
self->rx_pcr_register->R = pcr.R;
|
||||
psmi.B.PADSEL = self->rx_padsel_value;
|
||||
self->rx_psmi_register->R = psmi.R;
|
||||
pcr.R = 0;
|
||||
pcr.B.OBE = 1;
|
||||
pcr.B.PA = self->tx_pa_value;
|
||||
self->tx_pcr_register->R = pcr.R;
|
||||
|
||||
rv = rtems_termios_set_initial_baud(tty, BSP_DEFAULT_BAUD_RATE);
|
||||
if (rv != 0) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_BAUD);
|
||||
}
|
||||
|
||||
rv = mpc55xx_linflex_set_attributes(minor, &tty->termios);
|
||||
if (rv != 0) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ATTRIBUTES);
|
||||
}
|
||||
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
self->irq_rxi,
|
||||
"LINFlexD RXI",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
MPC55XX_INTC_DEFAULT_PRIORITY,
|
||||
mpc55xx_linflex_rx_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_INSTALL);
|
||||
}
|
||||
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
self->irq_txi,
|
||||
"LINFlexD TXI",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
MPC55XX_INTC_DEFAULT_PRIORITY,
|
||||
mpc55xx_linflex_tx_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_INSTALL);
|
||||
}
|
||||
|
||||
/*
|
||||
sc = mpc55xx_interrupt_handler_install(
|
||||
self->irq_err,
|
||||
"LINFlexD ERR",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
MPC55XX_INTC_DEFAULT_PRIORITY,
|
||||
mpc55xx_linflex_err_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_INSTALL);
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_linflex_last_close(int major, int minor, void* arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
SIU_PCR_tag pcr = { .R = 0 };
|
||||
SIUL_PSMI_8B_tag psmi = { .R = 0 };
|
||||
|
||||
/* enter initialization mode */
|
||||
enter_init_mode(regs);
|
||||
|
||||
/* disable interrupts */
|
||||
regs->LINIER.R = 0;
|
||||
|
||||
/* set module to sleep mode */
|
||||
enter_sleep_mode(regs);
|
||||
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
self->irq_rxi,
|
||||
mpc55xx_linflex_rx_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_RX_IRQ_REMOVE);
|
||||
}
|
||||
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
self->irq_txi,
|
||||
mpc55xx_linflex_tx_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_TX_IRQ_REMOVE);
|
||||
}
|
||||
|
||||
/*
|
||||
sc = rtems_interrupt_handler_remove(
|
||||
self->irq_err,
|
||||
mpc55xx_linflex_err_interrupt_handler,
|
||||
self
|
||||
);
|
||||
if (sc != RTEMS_SUCCESSFUL) {
|
||||
bsp_fatal(MPC55XX_FATAL_CONSOLE_LINFLEX_ERR_IRQ_REMOVE);
|
||||
}
|
||||
*/
|
||||
|
||||
pcr.B.IBE = 1;
|
||||
self->rx_pcr_register->R = pcr.R;
|
||||
self->tx_pcr_register->R = pcr.R;
|
||||
psmi.R = 0;
|
||||
self->rx_psmi_register->R = psmi.R;
|
||||
|
||||
self->tty = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpc55xx_linflex_poll_read(int minor)
|
||||
{
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
rtems_interrupt_level level;
|
||||
int c = -1;
|
||||
|
||||
rtems_interrupt_disable(level);
|
||||
if (regs->UARTSR.B.DRF_RFE != 0) {
|
||||
/* Clear flag */
|
||||
regs->UARTSR.B.DRF_RFE = 1;
|
||||
|
||||
/* Read */
|
||||
c = regs->BDRM.B.DATA4;
|
||||
}
|
||||
rtems_interrupt_enable(level);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static int mpc55xx_linflex_write(int minor, const char *out, size_t n)
|
||||
{
|
||||
if (n > 0) {
|
||||
mpc55xx_linflex_context *self = console_generic_get_context(minor);
|
||||
volatile LINFLEX_tag *regs = self->regs;
|
||||
|
||||
regs->BDRL.B.DATA0 = out [0];
|
||||
self->transmit_in_progress = true;
|
||||
/* TODO: send more then one byte */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const console_generic_callbacks mpc55xx_linflex_callbacks = {
|
||||
.termios_callbacks = {
|
||||
.firstOpen = mpc55xx_linflex_first_open,
|
||||
.lastClose = mpc55xx_linflex_last_close,
|
||||
.write = mpc55xx_linflex_write,
|
||||
.setAttributes = mpc55xx_linflex_set_attributes,
|
||||
.outputUsesInterrupts = TERMIOS_IRQ_DRIVEN
|
||||
},
|
||||
.poll_read = mpc55xx_linflex_poll_read,
|
||||
.poll_write = mpc55xx_linflex_poll_write
|
||||
};
|
||||
|
||||
#endif /* MPC55XX_HAS_LINFLEX */
|
||||
458
bsps/powerpc/mpc8260ads/console/console.c
Normal file
458
bsps/powerpc/mpc8260ads/console/console.c
Normal file
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* This file contains the MBX8xx termios serial I/O package.
|
||||
* Only asynchronous I/O is supported.
|
||||
*
|
||||
* The SCCs and SMCs are assigned as follows
|
||||
*
|
||||
* Channel Device Minor Note
|
||||
* SMC1 /dev/tty0 0
|
||||
* SMC2 /dev/tty1 1
|
||||
* SCC1 2 N/A. Hardwired as ethernet port
|
||||
* SCC2 /dev/tty2 3
|
||||
* SCC3 /dev/tty3 4
|
||||
* SCC4 /dev/tty4 5
|
||||
*
|
||||
* The SCCs and SMCs on the eval board are assigned as follows
|
||||
*
|
||||
* Channel Device Minor Termios
|
||||
* SMC1 /dev/tty3 4 no
|
||||
* SMC2 /dev/tty4 5 no
|
||||
* SCC1 /dev/tty0 0 no
|
||||
* SCC2 /dev/console 1 yes
|
||||
* SCC3 /dev/tty1 2 no * USED FOR NETWORK I/F
|
||||
* SCC4 /dev/tty2 3 no * USED FOR NETWORK I/F
|
||||
*
|
||||
* All ports support termios. The use of termios is recommended for real-time
|
||||
* applications. Termios provides buffering and input processing. When not
|
||||
* using termios, processing is limited to the substitution of LF for CR on
|
||||
* input, and the output of a CR following the output of a LF character.
|
||||
* Note that the terminal should not send CR/LF pairs when the return key
|
||||
* is pressed, and that output lines are terminated with LF/CR, not CR/LF
|
||||
* (although that would be easy to change).
|
||||
*
|
||||
* I/O may be interrupt-driven (recommended for real-time applications) or
|
||||
* polled. Polled I/O may be performed by this device driver entirely, or
|
||||
* in part by EPPCBug. With EPPCBug 1.1, polled I/O is limited to the
|
||||
* EPPCBug debug console. This is a limitation of the firmware. Later
|
||||
* firmware may be able to do I/O through any port. This code assumes
|
||||
* that the EPPCBug console is the default: SMC1. If the console and
|
||||
* printk ports are set to anything else with EPPCBug polled I/O, the
|
||||
* system will hang. Only port SMC1 is usable with EPPCBug polled I/O.
|
||||
*
|
||||
* LIMITATIONS:
|
||||
*
|
||||
* It is not possible to use different I/O modes on the different ports. The
|
||||
* exception is with printk. The printk port can use a different mode from
|
||||
* the other ports. If this is done, it is important not to open the printk
|
||||
* port from an RTEMS application.
|
||||
*
|
||||
* Currently, the I/O modes are determined at build time. It would be much
|
||||
* better to have the mode selected at boot time based on parameters in
|
||||
* NVRAM.
|
||||
*
|
||||
* Interrupt-driven I/O requires termios.
|
||||
*
|
||||
* TESTS:
|
||||
*
|
||||
* TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
|
||||
* play with the interrupt masks and turn off I/O. Those tests will hang
|
||||
* when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
|
||||
* from the static constructors before the console is open. This test
|
||||
* will not work with interrupt-driven I/O. Because of the buffering
|
||||
* performed in termios, test output may not be in sequence.The tests
|
||||
* should all be fixed to work with interrupt-driven I/O and to
|
||||
* produce output in the expected sequence. Obviously, the termios test
|
||||
* requires termios support in the driver.
|
||||
*
|
||||
* Set CONSOLE_MINOR to the appropriate device minor number in the
|
||||
* config file. This allows the RTEMS application console to be different
|
||||
* from the EPPBug debug console or the GDB port.
|
||||
*
|
||||
* This driver handles all five available serial ports: it distinguishes
|
||||
* the sub-devices using minor device numbers. It is not possible to have
|
||||
* other protocols running on the other ports when this driver is used as
|
||||
* currently written.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on code (alloc860.c in eth_comm port) by
|
||||
* Jay Monkman (jmonkman@frasca.com),
|
||||
* Copyright (C) 1998 by Frasca International, Inc.
|
||||
*
|
||||
* Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
|
||||
* and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>.
|
||||
* Copyright (c) 2000, National Research Council of Canada
|
||||
*
|
||||
* Modifications by Andy Dachs <iwe@fsmal.net> for MPC8260
|
||||
* support.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <bsp.h>
|
||||
|
||||
static void _BSP_output_char( char c );
|
||||
static rtems_status_code do_poll_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
|
||||
static rtems_status_code do_poll_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = _BSP_output_char;
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
|
||||
/*
|
||||
* do_poll_read
|
||||
*
|
||||
* Input characters through polled I/O. Returns has soon as a character has
|
||||
* been received. Otherwise, if we wait for the number of requested characters,
|
||||
* we could be here forever!
|
||||
*
|
||||
* CR is converted to LF on input. The terminal should not send a CR/LF pair
|
||||
* when the return or enter key is pressed.
|
||||
*
|
||||
* Input parameters:
|
||||
* major - ignored. Should be the major number for this driver.
|
||||
* minor - selected channel.
|
||||
* arg->buffer - where to put the received characters.
|
||||
* arg->count - number of characters to receive before returning--Ignored.
|
||||
*
|
||||
* Output parameters:
|
||||
* arg->bytes_moved - the number of characters read. Always 1.
|
||||
*
|
||||
* Return value: RTEMS_SUCCESSFUL
|
||||
*
|
||||
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
|
||||
*/
|
||||
static rtems_status_code do_poll_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void * arg
|
||||
)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = arg;
|
||||
int c;
|
||||
|
||||
#define BSP_READ m8xx_uart_pollRead
|
||||
|
||||
while( (c = BSP_READ(minor)) == -1 );
|
||||
rw_args->buffer[0] = (uint8_t)c;
|
||||
if( rw_args->buffer[0] == '\r' )
|
||||
rw_args->buffer[0] = '\n';
|
||||
rw_args->bytes_moved = 1;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_poll_write
|
||||
*
|
||||
* Output characters through polled I/O. Returns only once every character has
|
||||
* been sent.
|
||||
*
|
||||
* CR is transmitted AFTER a LF on output.
|
||||
*
|
||||
* Input parameters:
|
||||
* major - ignored. Should be the major number for this driver.
|
||||
* minor - selected channel
|
||||
* arg->buffer - where to get the characters to transmit.
|
||||
* arg->count - the number of characters to transmit before returning.
|
||||
*
|
||||
* Output parameters:
|
||||
* arg->bytes_moved - the number of characters read
|
||||
*
|
||||
* Return value: RTEMS_SUCCESSFUL
|
||||
*
|
||||
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
|
||||
*/
|
||||
static rtems_status_code do_poll_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void * arg
|
||||
)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = arg;
|
||||
uint32_t i;
|
||||
char cr ='\r';
|
||||
|
||||
#define BSP_WRITE m8xx_uart_pollWrite
|
||||
|
||||
for( i = 0; i < rw_args->count; i++ ) {
|
||||
BSP_WRITE(minor, &(rw_args->buffer[i]), 1);
|
||||
if ( rw_args->buffer[i] == '\n' )
|
||||
BSP_WRITE(minor, &cr, 1);
|
||||
}
|
||||
rw_args->bytes_moved = i;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Print functions prototyped in bspIo.h
|
||||
*/
|
||||
|
||||
static void _BSP_output_char( char c )
|
||||
{
|
||||
/*
|
||||
* Can't rely on console_initialize having been called before this function
|
||||
* is used, so it may fail unless output is done through EPPC-Bug.
|
||||
*/
|
||||
#define PRINTK_WRITE m8xx_uart_pollWrite
|
||||
|
||||
PRINTK_WRITE( PRINTK_MINOR, &c, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
***************
|
||||
* BOILERPLATE *
|
||||
***************
|
||||
*
|
||||
* All these functions are prototyped in rtems/c/src/lib/include/console.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize and register the device
|
||||
*/
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code status;
|
||||
rtems_device_minor_number console_minor;
|
||||
|
||||
/*
|
||||
* Set up TERMIOS if needed
|
||||
*/
|
||||
|
||||
console_minor = CONSOLE_MINOR;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
|
||||
rtems_termios_initialize ();
|
||||
#else
|
||||
rtems_termios_initialize ();
|
||||
#endif /* UARTS_USE_TERMIOS */
|
||||
|
||||
/*
|
||||
* Do common initialization.
|
||||
*/
|
||||
m8xx_uart_initialize();
|
||||
|
||||
/*
|
||||
* Do device-specific initialization
|
||||
*/
|
||||
#if 0
|
||||
m8xx_uart_smc_initialize(SMC1_MINOR); /* /dev/tty4 */
|
||||
m8xx_uart_smc_initialize(SMC2_MINOR); /* /dev/tty5 */
|
||||
#endif
|
||||
|
||||
m8xx_uart_scc_initialize(SCC1_MINOR); /* /dev/tty0 */
|
||||
m8xx_uart_scc_initialize(SCC2_MINOR); /* /dev/tty1 */
|
||||
|
||||
#if 0 /* used as network connections */
|
||||
m8xx_uart_scc_initialize(SCC3_MINOR); /* /dev/tty2 */
|
||||
m8xx_uart_scc_initialize(SCC4_MINOR); /* /dev/tty3 */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set up interrupts
|
||||
*/
|
||||
m8xx_uart_interrupts_initialize();
|
||||
|
||||
status = rtems_io_register_name ("/dev/tty0", major, SCC1_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
chmod("/dev/tty0",0660);
|
||||
chown("/dev/tty0",2,0);
|
||||
|
||||
status = rtems_io_register_name ("/dev/tty1", major, SCC2_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
chmod("/dev/tty1",0660);
|
||||
chown("/dev/tty1",2,0);
|
||||
|
||||
#if 0
|
||||
status = rtems_io_register_name ("/dev/tty2", major, SCC3_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
status = rtems_io_register_name ("/dev/tty3", major, SCC4_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
status = rtems_io_register_name ("/dev/tty4", major, SMC1_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
status = rtems_io_register_name ("/dev/tty5", major, SMC2_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
#endif
|
||||
/* Now register the RTEMS console */
|
||||
status = rtems_io_register_name ("/dev/console", major, console_minor);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
chmod("/dev/console",0666);
|
||||
chown("/dev/console",2,0);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the device
|
||||
*/
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
#if UARTS_IO_MODE == 1 /* RTEMS interrupt-driven I/O with termios */
|
||||
/* Used to track termios private data for callbacks */
|
||||
extern struct rtems_termios_tty *ttyp[];
|
||||
rtems_libio_open_close_args_t *args = arg;
|
||||
|
||||
static const rtems_termios_callbacks intrCallbacks = {
|
||||
NULL, /* firstOpen */
|
||||
NULL, /* lastClose */
|
||||
NULL, /* pollRead */
|
||||
m8xx_uart_write, /* write */
|
||||
m8xx_uart_setAttributes, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
1 /* outputUsesInterrupts */
|
||||
};
|
||||
#else
|
||||
#if (UARTS_USE_TERMIOS == 1) && (UARTS_IO_MODE != 1)
|
||||
static const rtems_termios_callbacks pollCallbacks = {
|
||||
NULL, /* firstOpen */
|
||||
NULL, /* lastClose */
|
||||
m8xx_uart_pollRead, /* pollRead */
|
||||
m8xx_uart_pollWrite, /* write */
|
||||
m8xx_uart_setAttributes, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
0 /* outputUsesInterrupts */
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
rtems_status_code sc;
|
||||
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
|
||||
#if UARTS_IO_MODE == 1 /* RTEMS interrupt-driven I/O with termios */
|
||||
sc = rtems_termios_open( major, minor, arg, &intrCallbacks );
|
||||
ttyp[minor] = args->iop->data1; /* Keep cookie returned by termios_open */
|
||||
#else /* RTEMS polled I/O with termios */
|
||||
sc = rtems_termios_open( major, minor, arg, &pollCallbacks );
|
||||
#endif
|
||||
|
||||
#else /* UARTS_USE_TERMIOS != 1 */
|
||||
/* no termios -- default to polled I/O */
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
#endif /* UARTS_USE_TERMIOS != 1 */
|
||||
|
||||
return sc;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the device
|
||||
*/
|
||||
rtems_device_driver console_close(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_close( arg );
|
||||
#else
|
||||
return RTEMS_SUCCESSFUL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the device
|
||||
*/
|
||||
rtems_device_driver console_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_read( arg );
|
||||
#else
|
||||
return do_poll_read( major, minor, arg );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the device
|
||||
*/
|
||||
rtems_device_driver console_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_write( arg );
|
||||
#else
|
||||
/* no termios -- default to polled */
|
||||
return do_poll_write( major, minor, arg );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle ioctl request.
|
||||
*/
|
||||
rtems_device_driver console_control(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_ioctl( arg );
|
||||
#else
|
||||
return RTEMS_SUCCESSFUL;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Support routine for console-generic
|
||||
*/
|
||||
int mbx8xx_console_get_configuration(void)
|
||||
{
|
||||
#if UARTS_IO_MODE == 1
|
||||
return 0x02;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
78
bsps/powerpc/psim/console/console-io.c
Normal file
78
bsps/powerpc/psim/console/console-io.c
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file contains the hardware specific portions of the TTY driver
|
||||
* for the simulated serial port on the PowerPC simulator.
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1989-2004.
|
||||
* 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 <bsp.h>
|
||||
#include <bsp/console-polled.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* console_initialize_hardware
|
||||
*
|
||||
* This routine initializes the console hardware.
|
||||
*
|
||||
*/
|
||||
|
||||
void console_initialize_hardware(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* external prototypes for monitor interface routines */
|
||||
|
||||
void outbyte( char );
|
||||
char inbyte( void );
|
||||
|
||||
/*
|
||||
* console_outbyte_polled
|
||||
*
|
||||
* This routine transmits a character using polling.
|
||||
*/
|
||||
|
||||
void console_outbyte_polled(
|
||||
int port,
|
||||
char ch
|
||||
)
|
||||
{
|
||||
outbyte( ch );
|
||||
}
|
||||
|
||||
/*
|
||||
* console_inbyte_nonblocking
|
||||
*
|
||||
* This routine polls for a character.
|
||||
*/
|
||||
|
||||
int console_inbyte_nonblocking(
|
||||
int port
|
||||
)
|
||||
{
|
||||
char c;
|
||||
|
||||
c = inbyte();
|
||||
if (!c)
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* To support printk
|
||||
*/
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
static void PSIM_output_char(char c) { console_outbyte_polled( 0, c ); }
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = PSIM_output_char;
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
33
bsps/powerpc/psim/console/consupp.S
Normal file
33
bsps/powerpc/psim/console/consupp.S
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Adapted from the mvme-inbyte.S and mvme-outbyte.S files in libgloss.
|
||||
* These should work on all targets using the ppcbug monitor.
|
||||
*
|
||||
* Copyright (c) 1995 Cygnus Support
|
||||
*
|
||||
* The authors hereby grant permission to use, copy, modify, distribute,
|
||||
* and license this software and its documentation for any purpose, provided
|
||||
* that existing copyright notices are retained in all copies and that this
|
||||
* notice is included verbatim in any distributions. No written agreement,
|
||||
* license, or royalty fee is required for any of the authorized uses.
|
||||
* Modifications to this software may be copyrighted by their authors
|
||||
* and need not follow the licensing terms described here, provided that
|
||||
* the new terms are clearly indicated on the first page of each file where
|
||||
* they apply.
|
||||
*/
|
||||
|
||||
#include "ppc-asm.h"
|
||||
|
||||
.file "support.s"
|
||||
.text
|
||||
FUNC_START(outbyte)
|
||||
li r10,0x20
|
||||
sc
|
||||
blr
|
||||
FUNC_END(outbyte)
|
||||
|
||||
.text
|
||||
FUNC_START(inbyte)
|
||||
li r10,0x0
|
||||
sc
|
||||
blr
|
||||
FUNC_END(inbyte)
|
||||
77
bsps/powerpc/qemuppc/console/console-io.c
Normal file
77
bsps/powerpc/qemuppc/console/console-io.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file contains the hardware specific portions of the TTY driver
|
||||
* for the serial ports on the qemuppc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* COPYRIGHT (c) 1989-2008.
|
||||
* 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 <bsp.h>
|
||||
#include <bsp/console-polled.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
static void
|
||||
__outb(int port, unsigned char v)
|
||||
{
|
||||
*((volatile unsigned char *)(0x80000000 + port)) = v;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
__inb(int port)
|
||||
{
|
||||
return *((volatile unsigned char *)(0x80000000 + port));
|
||||
}
|
||||
|
||||
/*
|
||||
* console_initialize_hardware
|
||||
*
|
||||
* This routine initializes the console hardware.
|
||||
*
|
||||
*/
|
||||
void console_initialize_hardware(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* console_outbyte_polled
|
||||
*
|
||||
* This routine transmits a character using polling.
|
||||
*/
|
||||
void console_outbyte_polled(
|
||||
int port,
|
||||
char ch
|
||||
)
|
||||
{
|
||||
__outb(0x3f8 + 0x00, ch);
|
||||
}
|
||||
|
||||
/*
|
||||
* console_inbyte_nonblocking
|
||||
*
|
||||
* This routine polls for a character.
|
||||
*/
|
||||
int console_inbyte_nonblocking(
|
||||
int port
|
||||
)
|
||||
{
|
||||
|
||||
if ( __inb(0x3f8 + 0x05) & 0x01 )
|
||||
return __inb(0x3f8 + 0x00);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
static void simBSP_output_char(char c) { console_outbyte_polled( 0, c ); }
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = simBSP_output_char;
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
330
bsps/powerpc/qoriq/console/console-config.c
Normal file
330
bsps/powerpc/qoriq/console/console-config.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup QorIQ
|
||||
*
|
||||
* @brief Console configuration.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010, 2017 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <string.h>
|
||||
|
||||
#include <libfdt.h>
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
|
||||
#include <libchip/ns16550.h>
|
||||
|
||||
#include <asm/epapr_hcalls.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/fdt.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/qoriq.h>
|
||||
#include <bsp/intercom.h>
|
||||
#include <bsp/uart-bridge.h>
|
||||
#include <bsp/console-termios.h>
|
||||
|
||||
static void output_char(char c);
|
||||
|
||||
#ifdef QORIQ_IS_HYPERVISOR_GUEST
|
||||
typedef struct {
|
||||
rtems_termios_device_context base;
|
||||
uint32_t handle;
|
||||
} qoriq_bc_context;
|
||||
|
||||
static bool qoriq_bc_probe(rtems_termios_device_context *base)
|
||||
{
|
||||
qoriq_bc_context *ctx;
|
||||
const void *fdt;
|
||||
int node;
|
||||
const uint32_t *handle;
|
||||
int len;
|
||||
|
||||
fdt = bsp_fdt_get();
|
||||
|
||||
node = fdt_node_offset_by_compatible(fdt, -1, "epapr,hv-byte-channel");
|
||||
if (node < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = fdt_getprop(fdt, node, "hv-handle", &len);
|
||||
if (handle == NULL || len != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctx = (qoriq_bc_context *) base;
|
||||
ctx->handle = fdt32_to_cpu(*handle);
|
||||
|
||||
BSP_output_char = output_char;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int qoriq_bc_read_polled(rtems_termios_device_context *base)
|
||||
{
|
||||
qoriq_bc_context *ctx;
|
||||
char buf[EV_BYTE_CHANNEL_MAX_BYTES];
|
||||
unsigned int count;
|
||||
unsigned int status;
|
||||
|
||||
ctx = (qoriq_bc_context *) base;
|
||||
count = 1;
|
||||
status = ev_byte_channel_receive(ctx->handle, &count, buf);
|
||||
|
||||
if (status != EV_SUCCESS || count == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (unsigned char) buf[0];
|
||||
}
|
||||
|
||||
static void qoriq_bc_write_polled(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
qoriq_bc_context *ctx;
|
||||
uint32_t handle;
|
||||
|
||||
ctx = (qoriq_bc_context *) base;
|
||||
handle = ctx->handle;
|
||||
|
||||
while (len > 0) {
|
||||
unsigned int count;
|
||||
unsigned int status;
|
||||
char buf2[EV_BYTE_CHANNEL_MAX_BYTES];
|
||||
const char *out;
|
||||
|
||||
if (len < EV_BYTE_CHANNEL_MAX_BYTES) {
|
||||
count = len;
|
||||
out = memcpy(buf2, buf, len);
|
||||
} else {
|
||||
count = EV_BYTE_CHANNEL_MAX_BYTES;
|
||||
out = buf;
|
||||
}
|
||||
|
||||
status = ev_byte_channel_send(handle, &count, out);
|
||||
|
||||
if (status == EV_SUCCESS) {
|
||||
len -= count;
|
||||
buf += count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const rtems_termios_device_handler qoriq_bc_handler_polled = {
|
||||
.poll_read = qoriq_bc_read_polled,
|
||||
.write = qoriq_bc_write_polled,
|
||||
.mode = TERMIOS_POLLED
|
||||
};
|
||||
|
||||
static qoriq_bc_context qoriq_bc_context_0 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("BC 0"),
|
||||
};
|
||||
#endif /* QORIQ_IS_HYPERVISOR_GUEST */
|
||||
|
||||
#if (QORIQ_UART_0_ENABLE + QORIQ_UART_BRIDGE_0_ENABLE == 2) \
|
||||
|| (QORIQ_UART_1_ENABLE + QORIQ_UART_BRIDGE_1_ENABLE == 2)
|
||||
#define BRIDGE_MASTER
|
||||
#elif QORIQ_UART_BRIDGE_0_ENABLE || QORIQ_UART_BRIDGE_1_ENABLE
|
||||
#define BRIDGE_SLAVE
|
||||
#endif
|
||||
|
||||
#ifdef BSP_USE_UART_INTERRUPTS
|
||||
#define DEVICE_FNS &ns16550_handler_interrupt
|
||||
#else
|
||||
#define DEVICE_FNS &ns16550_handler_polled
|
||||
#endif
|
||||
|
||||
#if QORIQ_UART_0_ENABLE || QORIQ_UART_1_ENABLE
|
||||
static bool uart_probe(rtems_termios_device_context *base)
|
||||
{
|
||||
ns16550_context *ctx = (ns16550_context *) base;
|
||||
|
||||
ctx->clock = BSP_bus_frequency;
|
||||
|
||||
return ns16550_probe(base);
|
||||
}
|
||||
|
||||
static uint8_t get_register(uintptr_t addr, uint8_t i)
|
||||
{
|
||||
volatile uint8_t *reg = (uint8_t *) addr;
|
||||
|
||||
return reg [i];
|
||||
}
|
||||
|
||||
static void set_register(uintptr_t addr, uint8_t i, uint8_t val)
|
||||
{
|
||||
volatile uint8_t *reg = (uint8_t *) addr;
|
||||
|
||||
reg [i] = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QORIQ_UART_0_ENABLE
|
||||
static ns16550_context qoriq_uart_context_0 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"),
|
||||
.get_reg = get_register,
|
||||
.set_reg = set_register,
|
||||
.port = (uintptr_t) &qoriq.uart_0,
|
||||
.irq = QORIQ_IRQ_DUART_1,
|
||||
.initial_baud = BSP_CONSOLE_BAUD
|
||||
};
|
||||
#endif
|
||||
|
||||
#if QORIQ_UART_1_ENABLE
|
||||
static ns16550_context qoriq_uart_context_1 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"),
|
||||
.get_reg = get_register,
|
||||
.set_reg = set_register,
|
||||
.port = (uintptr_t) &qoriq.uart_1,
|
||||
.irq = QORIQ_IRQ_DUART_1,
|
||||
.initial_baud = BSP_CONSOLE_BAUD
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef BRIDGE_MASTER
|
||||
#define BRIDGE_PROBE qoriq_uart_bridge_master_probe
|
||||
#define BRIDGE_FNS &qoriq_uart_bridge_master
|
||||
#if QORIQ_UART_BRIDGE_0_ENABLE
|
||||
static uart_bridge_master_context bridge_0_context = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"),
|
||||
.device_path = "/dev/ttyS0",
|
||||
.type = INTERCOM_TYPE_UART_0,
|
||||
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
|
||||
bridge_0_context.transmit_fifo
|
||||
)
|
||||
};
|
||||
#define BRIDGE_0_CONTEXT &bridge_0_context.base
|
||||
#endif
|
||||
#if QORIQ_UART_BRIDGE_1_ENABLE
|
||||
static uart_bridge_master_context bridge_1_context = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"),
|
||||
.device_path = "/dev/ttyS1",
|
||||
.type = INTERCOM_TYPE_UART_1,
|
||||
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
|
||||
bridge_1_context.transmit_fifo
|
||||
)
|
||||
};
|
||||
#define BRIDGE_1_CONTEXT &bridge_1_context.base
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BRIDGE_SLAVE
|
||||
#define BRIDGE_PROBE console_device_probe_default
|
||||
#define BRIDGE_FNS &qoriq_uart_bridge_slave
|
||||
#if QORIQ_UART_BRIDGE_0_ENABLE
|
||||
static uart_bridge_slave_context bridge_0_context = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"),
|
||||
.type = INTERCOM_TYPE_UART_0,
|
||||
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
|
||||
bridge_0_context.transmit_fifo
|
||||
)
|
||||
};
|
||||
#define BRIDGE_0_CONTEXT &bridge_0_context.base
|
||||
#endif
|
||||
#if QORIQ_UART_BRIDGE_1_ENABLE
|
||||
static uart_bridge_slave_context bridge_1_context = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"),
|
||||
.type = INTERCOM_TYPE_UART_1,
|
||||
.transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY(
|
||||
bridge_1_context.transmit_fifo
|
||||
)
|
||||
};
|
||||
#define BRIDGE_1_CONTEXT &bridge_1_context.base
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const console_device console_device_table[] = {
|
||||
#ifdef QORIQ_IS_HYPERVISOR_GUEST
|
||||
{
|
||||
.device_file = "/dev/ttyBC0",
|
||||
.probe = qoriq_bc_probe,
|
||||
.handler = &qoriq_bc_handler_polled,
|
||||
.context = &qoriq_bc_context_0.base
|
||||
},
|
||||
#endif
|
||||
#if QORIQ_UART_0_ENABLE
|
||||
{
|
||||
.device_file = "/dev/ttyS0",
|
||||
.probe = uart_probe,
|
||||
.handler = DEVICE_FNS,
|
||||
.context = &qoriq_uart_context_0.base
|
||||
},
|
||||
#endif
|
||||
#if QORIQ_UART_1_ENABLE
|
||||
{
|
||||
.device_file = "/dev/ttyS1",
|
||||
.probe = uart_probe,
|
||||
.handler = DEVICE_FNS,
|
||||
.context = &qoriq_uart_context_1.base
|
||||
},
|
||||
#endif
|
||||
#if QORIQ_UART_BRIDGE_0_ENABLE
|
||||
{
|
||||
#if QORIQ_UART_1_ENABLE
|
||||
.device_file = "/dev/ttyB0",
|
||||
#else
|
||||
.device_file = "/dev/ttyS0",
|
||||
#endif
|
||||
.probe = BRIDGE_PROBE,
|
||||
.handler = BRIDGE_FNS,
|
||||
.context = BRIDGE_0_CONTEXT
|
||||
},
|
||||
#endif
|
||||
#if QORIQ_UART_BRIDGE_1_ENABLE
|
||||
{
|
||||
#if QORIQ_UART_1_ENABLE
|
||||
.device_file = "/dev/ttyB1",
|
||||
#else
|
||||
.device_file = "/dev/ttyS1",
|
||||
#endif
|
||||
.probe = BRIDGE_PROBE,
|
||||
.handler = BRIDGE_FNS,
|
||||
.context = BRIDGE_1_CONTEXT
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table);
|
||||
|
||||
static void output_char(char c)
|
||||
{
|
||||
rtems_termios_device_context *base = console_device_table[0].context;
|
||||
|
||||
#ifdef QORIQ_IS_HYPERVISOR_GUEST
|
||||
qoriq_bc_write_polled(base, &c, 1);
|
||||
#else
|
||||
ns16550_polled_putchar(base, c);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef QORIQ_IS_HYPERVISOR_GUEST
|
||||
static void qoriq_bc_output_char_init(char c)
|
||||
{
|
||||
rtems_termios_device_context *base = console_device_table[0].context;
|
||||
|
||||
qoriq_bc_probe(base);
|
||||
output_char(c);
|
||||
}
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = qoriq_bc_output_char_init;
|
||||
#else
|
||||
BSP_output_char_function_type BSP_output_char = output_char;
|
||||
#endif
|
||||
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
181
bsps/powerpc/qoriq/console/uart-bridge-master.c
Normal file
181
bsps/powerpc/qoriq/console/uart-bridge-master.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup QorIQUartBridge
|
||||
*
|
||||
* @brief UART bridge master implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011-2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <bspopts.h>
|
||||
#include <bsp/uart-bridge.h>
|
||||
|
||||
#define TRANSMIT_EVENT RTEMS_EVENT_13
|
||||
|
||||
static void serial_settings(int fd)
|
||||
{
|
||||
struct termios term;
|
||||
int rv = tcgetattr(fd, &term);
|
||||
assert(rv == 0);
|
||||
|
||||
term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
||||
term.c_oflag &= ~OPOST;
|
||||
term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
term.c_cflag &= ~(CSIZE | PARENB);
|
||||
term.c_cflag |= CS8;
|
||||
|
||||
term.c_cc [VMIN] = 1;
|
||||
term.c_cc [VTIME] = 1;
|
||||
|
||||
rv = tcsetattr(fd, TCSANOW, &term);
|
||||
assert(rv == 0);
|
||||
}
|
||||
|
||||
static void uart_bridge_master_service(intercom_packet *packet, void *arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
uart_bridge_master_context *ctx = arg;
|
||||
|
||||
sc = rtems_chain_append_with_notification(
|
||||
&ctx->transmit_fifo,
|
||||
&packet->glue.node,
|
||||
ctx->transmit_task,
|
||||
TRANSMIT_EVENT
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void receive_task(rtems_task_argument arg)
|
||||
{
|
||||
uart_bridge_master_context *ctx = (uart_bridge_master_context *) arg;
|
||||
intercom_type type = ctx->type;
|
||||
|
||||
int fd = open(ctx->device_path, O_RDONLY);
|
||||
assert(fd >= 0);
|
||||
|
||||
serial_settings(fd);
|
||||
|
||||
while (true) {
|
||||
intercom_packet *packet = qoriq_intercom_allocate_packet(
|
||||
type,
|
||||
INTERCOM_SIZE_64
|
||||
);
|
||||
ssize_t in = read(fd, packet->data, packet->size - 1);
|
||||
if (in > 0) {
|
||||
packet->size = (size_t) in;
|
||||
qoriq_intercom_send_packet(QORIQ_UART_BRIDGE_SLAVE_CORE, packet);
|
||||
} else {
|
||||
qoriq_intercom_free_packet(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transmit_task(rtems_task_argument arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
uart_bridge_master_context *ctx = (uart_bridge_master_context *) arg;
|
||||
rtems_chain_control *fifo = &ctx->transmit_fifo;
|
||||
|
||||
int fd = open(ctx->device_path, O_WRONLY);
|
||||
assert(fd >= 0);
|
||||
|
||||
serial_settings(fd);
|
||||
|
||||
while (true) {
|
||||
intercom_packet *packet = NULL;
|
||||
sc = rtems_chain_get_with_wait(
|
||||
fifo,
|
||||
TRANSMIT_EVENT,
|
||||
RTEMS_NO_TIMEOUT,
|
||||
(rtems_chain_node **) &packet
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
write(fd, packet->data, packet->size);
|
||||
qoriq_intercom_free_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
static rtems_id create_task(
|
||||
char name,
|
||||
rtems_task_entry entry,
|
||||
uart_bridge_master_context *ctx
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
rtems_id task = RTEMS_ID_NONE;
|
||||
char index = (char) ('0' + ctx->type - INTERCOM_TYPE_UART_0);
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('U', 'B', name, index),
|
||||
QORIQ_UART_BRIDGE_TASK_PRIORITY,
|
||||
0,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&task
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_start(
|
||||
task,
|
||||
entry,
|
||||
(rtems_task_argument) ctx
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
bool qoriq_uart_bridge_master_probe(rtems_termios_device_context *base)
|
||||
{
|
||||
uart_bridge_master_context *ctx = (uart_bridge_master_context *) base;
|
||||
intercom_type type = ctx->type;
|
||||
|
||||
qoriq_intercom_service_install(type, uart_bridge_master_service, ctx);
|
||||
create_task('R', receive_task, ctx);
|
||||
ctx->transmit_task = create_task('T', transmit_task, ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool first_open(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
struct termios *term,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool set_attributes(
|
||||
rtems_termios_device_context *base,
|
||||
const struct termios *term
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const rtems_termios_device_handler qoriq_uart_bridge_master = {
|
||||
.first_open = first_open,
|
||||
.set_attributes = set_attributes,
|
||||
.mode = TERMIOS_POLLED
|
||||
};
|
||||
195
bsps/powerpc/qoriq/console/uart-bridge-slave.c
Normal file
195
bsps/powerpc/qoriq/console/uart-bridge-slave.c
Normal file
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup QorIQUartBridge
|
||||
*
|
||||
* @brief UART bridge slave implementation.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Obere Lagerstr. 30
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <libchip/sersupp.h>
|
||||
|
||||
#include <bspopts.h>
|
||||
#include <bsp/uart-bridge.h>
|
||||
|
||||
#define TRANSMIT_EVENT RTEMS_EVENT_13
|
||||
|
||||
static rtems_mode disable_preemption(void)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
rtems_mode prev_mode = 0;
|
||||
|
||||
sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
return prev_mode;
|
||||
}
|
||||
|
||||
static void restore_preemption(rtems_mode prev_mode)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
|
||||
sc = rtems_task_mode (prev_mode, RTEMS_PREEMPT_MASK, &prev_mode);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
static void uart_bridge_slave_service(intercom_packet *packet, void *arg)
|
||||
{
|
||||
uart_bridge_slave_context *ctx = arg;
|
||||
struct rtems_termios_tty *tty = ctx->tty;
|
||||
|
||||
/* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
|
||||
rtems_mode prev_mode = disable_preemption();
|
||||
|
||||
rtems_termios_enqueue_raw_characters(tty, packet->data, (int) packet->size);
|
||||
qoriq_intercom_free_packet(packet);
|
||||
|
||||
restore_preemption(prev_mode);
|
||||
}
|
||||
|
||||
static void transmit_task(rtems_task_argument arg)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) arg;
|
||||
rtems_chain_control *fifo = &ctx->transmit_fifo;
|
||||
struct rtems_termios_tty *tty = ctx->tty;
|
||||
|
||||
while (true) {
|
||||
intercom_packet *packet = NULL;
|
||||
sc = rtems_chain_get_with_wait(
|
||||
fifo,
|
||||
TRANSMIT_EVENT,
|
||||
RTEMS_NO_TIMEOUT,
|
||||
(rtems_chain_node **) &packet
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
/* Workaround for https://www.rtems.org/bugzilla/show_bug.cgi?id=1736 */
|
||||
rtems_mode prev_mode = disable_preemption();
|
||||
|
||||
size_t size = packet->size;
|
||||
qoriq_intercom_send_packet(QORIQ_UART_BRIDGE_MASTER_CORE, packet);
|
||||
rtems_termios_dequeue_characters(tty, (int) size);
|
||||
|
||||
restore_preemption(prev_mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_transmit_task(
|
||||
uart_bridge_slave_context *ctx
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
rtems_id task = RTEMS_ID_NONE;
|
||||
char index = (char) ('0' + ctx->type - INTERCOM_TYPE_UART_0);
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('U', 'B', 'T', index),
|
||||
QORIQ_UART_BRIDGE_TASK_PRIORITY,
|
||||
0,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&task
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_start(
|
||||
task,
|
||||
transmit_task,
|
||||
(rtems_task_argument) ctx
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
ctx->transmit_task = task;
|
||||
}
|
||||
|
||||
static bool first_open(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
struct termios *term,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
|
||||
intercom_type type = ctx->type;
|
||||
|
||||
ctx->tty = tty;
|
||||
rtems_termios_set_initial_baud(tty, 115200);
|
||||
create_transmit_task(ctx);
|
||||
qoriq_intercom_service_install(type, uart_bridge_slave_service, ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void last_close(
|
||||
struct rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
|
||||
|
||||
qoriq_intercom_service_remove(ctx->type);
|
||||
}
|
||||
|
||||
static void write_with_interrupts(
|
||||
rtems_termios_device_context *base,
|
||||
const char *buf,
|
||||
size_t len
|
||||
)
|
||||
{
|
||||
if (len > 0) {
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
uart_bridge_slave_context *ctx = (uart_bridge_slave_context *) base;
|
||||
intercom_packet *packet = qoriq_intercom_allocate_packet(
|
||||
ctx->type,
|
||||
INTERCOM_SIZE_64
|
||||
);
|
||||
|
||||
packet->size = len;
|
||||
memcpy(packet->data, buf, len);
|
||||
|
||||
/*
|
||||
* Due to the lovely Termios implementation we have to hand this over to
|
||||
* another context.
|
||||
*/
|
||||
sc = rtems_chain_append_with_notification(
|
||||
&ctx->transmit_fifo,
|
||||
&packet->glue.node,
|
||||
ctx->transmit_task,
|
||||
TRANSMIT_EVENT
|
||||
);
|
||||
assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool set_attributes(
|
||||
rtems_termios_device_context *base,
|
||||
const struct termios *term
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const rtems_termios_device_handler qoriq_uart_bridge_slave = {
|
||||
.first_open = first_open,
|
||||
.last_close = last_close,
|
||||
.write = write_with_interrupts,
|
||||
.set_attributes = set_attributes,
|
||||
.mode = TERMIOS_IRQ_DRIVEN
|
||||
};
|
||||
314
bsps/powerpc/shared/console/console.c
Normal file
314
bsps/powerpc/shared/console/console.c
Normal file
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* console.c -- console I/O package
|
||||
*
|
||||
* Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
|
||||
*
|
||||
* This code is based on the pc386 BSP console.c so the following
|
||||
* copyright also applies :
|
||||
*
|
||||
* (C) Copyright 1997 -
|
||||
* - NavIST Group - Real-Time Distributed Systems and Industrial Automation
|
||||
*
|
||||
* Till Straumann, <strauman@slac.stanford.edu>, 12/20/2001
|
||||
* separate BSP specific stuff from generics...
|
||||
*
|
||||
* http://pandora.ist.utl.pt
|
||||
*
|
||||
* Instituto Superior Tecnico * Lisboa * PORTUGAL
|
||||
* 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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
#include <termios.h>
|
||||
#include <bsp/uart.h>
|
||||
#include <rtems/bspIo.h> /* printk */
|
||||
|
||||
/* Definitions for BSPConsolePort */
|
||||
/*
|
||||
* Possible value for console input/output :
|
||||
* BSP_CONSOLE_PORT_CONSOLE
|
||||
* BSP_UART_COM1
|
||||
* BSP_UART_COM2
|
||||
*/
|
||||
int BSPConsolePort = BSP_CONSOLE_PORT;
|
||||
|
||||
int BSPBaseBaud = BSP_UART_BAUD_BASE;
|
||||
|
||||
/*
|
||||
* TERMIOS_OUTPUT_MODE should be a 'bspopts.h/configure'-able option;
|
||||
* we could even make it a link-time option (but that would require
|
||||
* small changes)...
|
||||
*/
|
||||
#if defined(USE_POLLED_IO)
|
||||
#define TERMIOS_OUTPUT_MODE TERMIOS_POLLED
|
||||
#elif defined(USE_TASK_DRIVEN_IO)
|
||||
#define TERMIOS_OUTPUT_MODE TERMIOS_TASK_DRIVEN
|
||||
#else
|
||||
#define TERMIOS_OUTPUT_MODE TERMIOS_IRQ_DRIVEN
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| External Prototypes
|
||||
+--------------------------------------------------------------------------*/
|
||||
|
||||
static int conSetAttr(int minor, const struct termios *);
|
||||
|
||||
typedef struct TtySTblRec_ {
|
||||
char *name;
|
||||
rtems_irq_hdl isr;
|
||||
} TtySTblRec, *TtySTbl;
|
||||
|
||||
static TtySTblRec ttyS[]={
|
||||
{ "/dev/ttyS0",
|
||||
#ifdef BSP_UART_IOBASE_COM1
|
||||
BSP_uart_termios_isr_com1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
{ "/dev/ttyS1",
|
||||
#ifdef BSP_UART_IOBASE_COM2
|
||||
BSP_uart_termios_isr_com2
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Console device driver INITIALIZE entry point.
|
||||
+--------------------------------------------------------------------------+
|
||||
| Initilizes the I/O console (keyboard + VGA display) driver.
|
||||
+--------------------------------------------------------------------------*/
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code status;
|
||||
|
||||
/*
|
||||
* The video was initialized in the start.s code and does not need
|
||||
* to be reinitialized.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set up TERMIOS
|
||||
*/
|
||||
rtems_termios_initialize();
|
||||
|
||||
/*
|
||||
* Do device-specific initialization
|
||||
*/
|
||||
|
||||
/* RTEMS calls this routine once with 'minor'==0; loop through
|
||||
* all known instances...
|
||||
*/
|
||||
|
||||
for (minor=0; minor < sizeof(ttyS)/sizeof(ttyS[0]); minor++) {
|
||||
char *nm;
|
||||
/*
|
||||
* Skip ports (possibly not supported by BSP...) we have no ISR for
|
||||
*/
|
||||
if ( ! ttyS[minor].isr )
|
||||
continue;
|
||||
/*
|
||||
* Register the device
|
||||
*/
|
||||
status = rtems_io_register_name ((nm=ttyS[minor].name), major, minor);
|
||||
if ( RTEMS_SUCCESSFUL==status && BSPConsolePort == minor) {
|
||||
printk("Registering /dev/console as minor %" PRIu32 " (==%s)\n",
|
||||
minor,
|
||||
ttyS[minor].name);
|
||||
/* also register an alias */
|
||||
status = rtems_io_register_name ( (nm="/dev/console"), major, minor);
|
||||
}
|
||||
|
||||
if (status != RTEMS_SUCCESSFUL) {
|
||||
printk("Error registering %s!\n",nm);
|
||||
rtems_fatal_error_occurred (status);
|
||||
}
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
} /* console_initialize */
|
||||
|
||||
#if !defined(USE_POLLED_IO)
|
||||
static int console_first_open(int major, int minor, void *arg)
|
||||
{
|
||||
rtems_status_code status;
|
||||
|
||||
/* must not open a minor device we have no ISR for */
|
||||
assert( minor>=0 && minor < sizeof(ttyS)/sizeof(ttyS[0]) && ttyS[minor].isr );
|
||||
|
||||
/* 9600-8-N-1 */
|
||||
BSP_uart_init(minor, 9600, 0);
|
||||
status = BSP_uart_install_isr(minor, ttyS[minor].isr);
|
||||
if (!status) {
|
||||
printk("Error installing serial console interrupt handler for '%s'!\n",
|
||||
ttyS[minor].name);
|
||||
rtems_fatal_error_occurred(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass data area info down to driver
|
||||
*/
|
||||
BSP_uart_termios_set(minor, ((rtems_libio_open_close_args_t *)arg)->iop->data1);
|
||||
|
||||
/* Enable interrupts on channel */
|
||||
BSP_uart_intr_ctrl(minor, BSP_UART_INTR_CTRL_TERMIOS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(USE_POLLED_IO)
|
||||
static int console_last_close(int major, int minor, void *arg)
|
||||
{
|
||||
BSP_uart_remove_isr(minor, ttyS[minor].isr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Console device driver OPEN entry point
|
||||
+--------------------------------------------------------------------------*/
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code status;
|
||||
static rtems_termios_callbacks cb =
|
||||
#if defined(USE_POLLED_IO)
|
||||
{
|
||||
NULL, /* firstOpen */
|
||||
NULL, /* lastClose */
|
||||
NULL, /* pollRead */
|
||||
BSP_uart_termios_write_polled, /* write */
|
||||
conSetAttr, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
TERMIOS_POLLED /* outputUsesInterrupts */
|
||||
};
|
||||
#else
|
||||
{
|
||||
console_first_open, /* firstOpen */
|
||||
console_last_close, /* lastClose */
|
||||
#ifdef USE_TASK_DRIVEN_IO
|
||||
BSP_uart_termios_read_com, /* pollRead */
|
||||
#else
|
||||
NULL, /* pollRead */
|
||||
#endif
|
||||
BSP_uart_termios_write_com, /* write */
|
||||
conSetAttr, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
TERMIOS_OUTPUT_MODE /* outputUsesInterrupts */
|
||||
};
|
||||
#endif
|
||||
|
||||
status = rtems_termios_open (major, minor, arg, &cb);
|
||||
|
||||
if (status != RTEMS_SUCCESSFUL) {
|
||||
printk("Error opening console device\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Console device driver CLOSE entry point
|
||||
+--------------------------------------------------------------------------*/
|
||||
rtems_device_driver
|
||||
console_close(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_device_driver res = RTEMS_SUCCESSFUL;
|
||||
|
||||
res = rtems_termios_close (arg);
|
||||
|
||||
return res;
|
||||
} /* console_close */
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Console device driver READ entry point.
|
||||
+--------------------------------------------------------------------------+
|
||||
| Read characters from the I/O console. We only have stdin.
|
||||
+--------------------------------------------------------------------------*/
|
||||
rtems_device_driver console_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
return rtems_termios_read (arg);
|
||||
} /* console_read */
|
||||
|
||||
/*-------------------------------------------------------------------------+
|
||||
| Console device driver WRITE entry point.
|
||||
+--------------------------------------------------------------------------+
|
||||
| Write characters to the I/O console. Stderr and stdout are the same.
|
||||
+--------------------------------------------------------------------------*/
|
||||
rtems_device_driver console_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
return rtems_termios_write (arg);
|
||||
} /* console_write */
|
||||
|
||||
/*
|
||||
* Handle ioctl request.
|
||||
*/
|
||||
rtems_device_driver console_control(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
/* does the BSP support break callbacks ? */
|
||||
#if defined(BIOCSETBREAKCB) && defined(BIOCGETBREAKCB)
|
||||
rtems_libio_ioctl_args_t *ioa=arg;
|
||||
switch (ioa->command) {
|
||||
case BIOCSETBREAKCB: return BSP_uart_set_break_cb(minor, ioa);
|
||||
case BIOCGETBREAKCB: return BSP_uart_get_break_cb(minor, ioa);
|
||||
default: break;
|
||||
}
|
||||
#endif
|
||||
return rtems_termios_ioctl (arg);
|
||||
}
|
||||
|
||||
static int conSetAttr(
|
||||
int minor,
|
||||
const struct termios *t
|
||||
)
|
||||
{
|
||||
rtems_termios_baud_t baud;
|
||||
|
||||
baud = rtems_termios_baud_to_number(t->c_ospeed);
|
||||
if ( baud > 115200 )
|
||||
rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR);
|
||||
|
||||
BSP_uart_set_baud(minor, baud);
|
||||
|
||||
return 0;
|
||||
}
|
||||
781
bsps/powerpc/shared/console/uart.c
Normal file
781
bsps/powerpc/shared/console/uart.c
Normal file
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* This software is Copyright (C) 1998 by T.sqware - all rights limited
|
||||
* It is provided in to the public domain "as is", can be freely modified
|
||||
* as far as this copyight notice is kept unchanged, but does not imply
|
||||
* an endorsement by T.sqware of the product in which it is included.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <bsp.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/uart.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
#include <termios.h>
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* Basic 16552 driver
|
||||
*/
|
||||
|
||||
struct uart_data
|
||||
{
|
||||
unsigned long ioBase;
|
||||
int irq;
|
||||
int hwFlow;
|
||||
int baud;
|
||||
BSP_UartBreakCbRec breakCallback;
|
||||
int ioMode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialization of BSP specific data.
|
||||
* The constants are pulled in from a BSP
|
||||
* specific file, whereas all of the code
|
||||
* in this file is generic and makes no
|
||||
* assumptions about addresses, irq vectors
|
||||
* etc...
|
||||
*/
|
||||
|
||||
#define UART_UNSUPP ((unsigned long)(-1))
|
||||
|
||||
static struct uart_data uart_data[2] = {
|
||||
{
|
||||
#ifdef BSP_UART_IOBASE_COM1
|
||||
BSP_UART_IOBASE_COM1,
|
||||
BSP_UART_COM1_IRQ,
|
||||
#else
|
||||
UART_UNSUPP,
|
||||
-1,
|
||||
#endif
|
||||
},
|
||||
{
|
||||
#ifdef BSP_UART_IOBASE_COM2
|
||||
BSP_UART_IOBASE_COM2,
|
||||
BSP_UART_COM2_IRQ,
|
||||
#else
|
||||
UART_UNSUPP,
|
||||
-1,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
#define MAX_UARTS (sizeof(uart_data)/sizeof(uart_data[0]))
|
||||
#define SANITY_CHECK(uart) \
|
||||
assert( MAX_UARTS > (unsigned)(uart) && uart_data[(uart)].ioBase != UART_UNSUPP )
|
||||
/*
|
||||
* Macros to read/write register of uart, if configuration is
|
||||
* different just rewrite these macros
|
||||
*/
|
||||
|
||||
static inline unsigned char
|
||||
uread(int uart, unsigned int reg)
|
||||
{
|
||||
return in_8((uint8_t*)(uart_data[uart].ioBase + reg));
|
||||
}
|
||||
|
||||
static inline void
|
||||
uwrite(int uart, int reg, unsigned int val)
|
||||
{
|
||||
out_8((uint8_t*)(uart_data[uart].ioBase + reg), val);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
uartError(int uart, void *termiosPrivate)
|
||||
{
|
||||
unsigned char uartStatus, dummy;
|
||||
BSP_UartBreakCbProc h;
|
||||
|
||||
uartStatus = uread(uart, LSR);
|
||||
dummy = uread(uart, RBR);
|
||||
|
||||
#ifdef UARTDEBUG
|
||||
if (uartStatus & OE)
|
||||
printk("********* Over run Error **********\n");
|
||||
if (uartStatus & PE)
|
||||
printk("********* Parity Error **********\n");
|
||||
if (uartStatus & FE)
|
||||
printk("********* Framing Error **********\n");
|
||||
if (uartStatus & BI) {
|
||||
printk("********* BREAK INTERRUPT *********\n");
|
||||
#endif
|
||||
if ((h=uart_data[uart].breakCallback.handler)) {
|
||||
h(uart,
|
||||
(dummy<<8)|uartStatus,
|
||||
termiosPrivate,
|
||||
uart_data[uart].breakCallback.private);
|
||||
}
|
||||
#ifdef UARTDEBUG
|
||||
if (uartStatus & ERFIFO)
|
||||
printk("********* Error receive Fifo **********\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Uart initialization, it is hardcoded to 8 bit, no parity,
|
||||
* one stop bit, FIFO, things to be changed
|
||||
* are baud rate and nad hw flow control,
|
||||
* and longest rx fifo setting
|
||||
*/
|
||||
void
|
||||
BSP_uart_init(int uart, int baud, int hwFlow)
|
||||
{
|
||||
unsigned char tmp;
|
||||
|
||||
/* Sanity check */
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
/* Make sure any printk activity drains before
|
||||
* re-initializing.
|
||||
*/
|
||||
while ( ! (uread(uart, LSR) & TEMT) )
|
||||
;
|
||||
|
||||
switch(baud)
|
||||
{
|
||||
case 50:
|
||||
case 75:
|
||||
case 110:
|
||||
case 134:
|
||||
case 300:
|
||||
case 600:
|
||||
case 1200:
|
||||
case 2400:
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set DLAB bit to 1 */
|
||||
uwrite(uart, LCR, DLAB);
|
||||
|
||||
if ( (int)BSPBaseBaud <= 0 ) {
|
||||
/* Use current divisor assuming BSPBaseBaud gives us the current speed */
|
||||
BSPBaseBaud = BSPBaseBaud ? -BSPBaseBaud : 9600;
|
||||
BSPBaseBaud *= ((uread(uart, DLM) << 8) | uread(uart, DLL));
|
||||
}
|
||||
|
||||
/* Set baud rate */
|
||||
uwrite(uart, DLL, (BSPBaseBaud/baud) & 0xff);
|
||||
uwrite(uart, DLM, ((BSPBaseBaud/baud) >> 8) & 0xff);
|
||||
|
||||
/* 8-bit, no parity , 1 stop */
|
||||
uwrite(uart, LCR, CHR_8_BITS);
|
||||
|
||||
/* Set DTR, RTS and OUT2 high */
|
||||
uwrite(uart, MCR, DTR | RTS | OUT_2);
|
||||
|
||||
/* Enable FIFO */
|
||||
uwrite(uart, FCR, FIFO_EN | XMIT_RESET | RCV_RESET | RECEIVE_FIFO_TRIGGER12);
|
||||
|
||||
/* Disable Interrupts */
|
||||
uwrite(uart, IER, 0);
|
||||
|
||||
/* Read status to clear them */
|
||||
tmp = uread(uart, LSR);
|
||||
tmp = uread(uart, RBR);
|
||||
tmp = uread(uart, MSR);
|
||||
(void) tmp; /* avoid set but not used warning */
|
||||
|
||||
/* Remember state */
|
||||
uart_data[uart].hwFlow = hwFlow;
|
||||
uart_data[uart].baud = baud;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set baud
|
||||
*/
|
||||
void
|
||||
BSP_uart_set_baud(int uart, int baud)
|
||||
{
|
||||
unsigned char mcr, ier;
|
||||
|
||||
/* Sanity check */
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
/*
|
||||
* This function may be called whenever TERMIOS parameters
|
||||
* are changed, so we have to make sure that baud change is
|
||||
* indeed required.
|
||||
*/
|
||||
|
||||
if(baud == uart_data[uart].baud)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mcr = uread(uart, MCR);
|
||||
ier = uread(uart, IER);
|
||||
|
||||
BSP_uart_init(uart, baud, uart_data[uart].hwFlow);
|
||||
|
||||
uwrite(uart, MCR, mcr);
|
||||
uwrite(uart, IER, ier);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/disable interrupts
|
||||
*/
|
||||
void
|
||||
BSP_uart_intr_ctrl(int uart, int cmd)
|
||||
{
|
||||
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case BSP_UART_INTR_CTRL_DISABLE:
|
||||
uwrite(uart, IER, INTERRUPT_DISABLE);
|
||||
break;
|
||||
case BSP_UART_INTR_CTRL_ENABLE:
|
||||
if(uart_data[uart].hwFlow)
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
TRANSMIT_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE |
|
||||
MODEM_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
TRANSMIT_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case BSP_UART_INTR_CTRL_TERMIOS:
|
||||
if(uart_data[uart].hwFlow)
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE |
|
||||
MODEM_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case BSP_UART_INTR_CTRL_GDB:
|
||||
uwrite(uart, IER, RECEIVE_ENABLE);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
BSP_uart_throttle(int uart)
|
||||
{
|
||||
unsigned int mcr;
|
||||
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
if(!uart_data[uart].hwFlow)
|
||||
{
|
||||
/* Should not happen */
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
mcr = uread (uart, MCR);
|
||||
/* RTS down */
|
||||
mcr &= ~RTS;
|
||||
uwrite(uart, MCR, mcr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
BSP_uart_unthrottle(int uart)
|
||||
{
|
||||
unsigned int mcr;
|
||||
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
if(!uart_data[uart].hwFlow)
|
||||
{
|
||||
/* Should not happen */
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
mcr = uread (uart, MCR);
|
||||
/* RTS up */
|
||||
mcr |= RTS;
|
||||
uwrite(uart, MCR, mcr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Status function, -1 if error
|
||||
* detected, 0 if no received chars available,
|
||||
* 1 if received char available, 2 if break
|
||||
* is detected, it will eat break and error
|
||||
* chars. It ignores overruns - we cannot do
|
||||
* anything about - it execpt count statistics
|
||||
* and we are not counting it.
|
||||
*/
|
||||
int
|
||||
BSP_uart_polled_status(int uart)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
val = uread(uart, LSR);
|
||||
|
||||
if(val & BI)
|
||||
{
|
||||
/* BREAK found, eat character */
|
||||
uread(uart, RBR);
|
||||
return BSP_UART_STATUS_BREAK;
|
||||
}
|
||||
|
||||
if((val & (DR | OE | FE)) == 1)
|
||||
{
|
||||
/* No error, character present */
|
||||
return BSP_UART_STATUS_CHAR;
|
||||
}
|
||||
|
||||
if((val & (DR | OE | FE)) == 0)
|
||||
{
|
||||
/* Nothing */
|
||||
return BSP_UART_STATUS_NOCHAR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Framing or parity error
|
||||
* eat character
|
||||
*/
|
||||
uread(uart, RBR);
|
||||
|
||||
return BSP_UART_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Polled mode write function
|
||||
*/
|
||||
void
|
||||
BSP_uart_polled_write(int uart, int val)
|
||||
{
|
||||
unsigned char val1;
|
||||
|
||||
/* Sanity check */
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if((val1=uread(uart, LSR)) & THRE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(uart_data[uart].hwFlow)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(uread(uart, MSR) & CTS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uwrite(uart, THR, val & 0xff);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
BSP_output_char_via_serial(const char val)
|
||||
{
|
||||
BSP_uart_polled_write(BSPConsolePort, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Polled mode read function
|
||||
*/
|
||||
int
|
||||
BSP_uart_polled_read(int uart)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
if(uread(uart, LSR) & DR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
val = uread(uart, RBR);
|
||||
|
||||
return (int)(val & 0xff);
|
||||
}
|
||||
|
||||
unsigned
|
||||
BSP_poll_char_via_serial()
|
||||
{
|
||||
return BSP_uart_polled_read(BSPConsolePort);
|
||||
}
|
||||
|
||||
static void
|
||||
uart_noop(const rtems_irq_connect_data *unused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* note that the IRQ names contain _ISA_ for legacy
|
||||
* reasons. They can be any interrupt, depending
|
||||
* on the particular BSP...
|
||||
*/
|
||||
|
||||
static int
|
||||
uart_isr_is_on(const rtems_irq_connect_data *irq)
|
||||
{
|
||||
int uart;
|
||||
|
||||
uart = (irq->name == BSP_UART_COM1_IRQ) ?
|
||||
BSP_UART_COM1 : BSP_UART_COM2;
|
||||
|
||||
return uread(uart,IER);
|
||||
}
|
||||
|
||||
static int
|
||||
doit(int uart, rtems_irq_hdl handler, int (*p)(const rtems_irq_connect_data*))
|
||||
{
|
||||
rtems_irq_connect_data d={0};
|
||||
d.name = uart_data[uart].irq;
|
||||
d.off = d.on = uart_noop;
|
||||
d.isOn = uart_isr_is_on;
|
||||
d.hdl = handler;
|
||||
return p(&d);
|
||||
}
|
||||
|
||||
int
|
||||
BSP_uart_install_isr(int uart, rtems_irq_hdl handler)
|
||||
{
|
||||
/* Using shared interrupts by default might break things.. the
|
||||
* shared IRQ installer uses malloc() and if a BSP had called this
|
||||
* during early init it might not work...
|
||||
*/
|
||||
#ifdef BSP_UART_USE_SHARED_IRQS
|
||||
return doit(uart, handler, BSP_install_rtems_shared_irq_handler);
|
||||
#else
|
||||
return doit(uart, handler, BSP_install_rtems_irq_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
BSP_uart_remove_isr(int uart, rtems_irq_hdl handler)
|
||||
{
|
||||
return doit(uart, handler, BSP_remove_rtems_irq_handler);
|
||||
}
|
||||
|
||||
/* ================ Termios support =================*/
|
||||
|
||||
static volatile int termios_stopped_com[2] = {0,0};
|
||||
static volatile int termios_tx_active_com[2] = {0,0};
|
||||
static void* termios_ttyp_com[2] = {NULL,NULL};
|
||||
static char termios_tx_hold_com[2] = {0,0};
|
||||
static volatile char termios_tx_hold_valid_com[2] = {0,0};
|
||||
|
||||
/*
|
||||
* Set channel parameters
|
||||
*/
|
||||
void
|
||||
BSP_uart_termios_set(int uart, void *p)
|
||||
{
|
||||
struct rtems_termios_tty *ttyp = p;
|
||||
unsigned char val;
|
||||
SANITY_CHECK(uart);
|
||||
|
||||
if(uart_data[uart].hwFlow)
|
||||
{
|
||||
val = uread(uart, MSR);
|
||||
|
||||
termios_stopped_com[uart] = (val & CTS) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
termios_stopped_com[uart] = 0;
|
||||
}
|
||||
termios_tx_active_com[uart] = 0;
|
||||
termios_ttyp_com[uart] = ttyp;
|
||||
termios_tx_hold_com[uart] = 0;
|
||||
termios_tx_hold_valid_com[uart] = 0;
|
||||
|
||||
uart_data[uart].ioMode = ttyp->device.outputUsesInterrupts;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
BSP_uart_termios_write_polled(int minor, const char *buf, size_t len)
|
||||
{
|
||||
int uart=minor; /* could differ, theoretically */
|
||||
int nwrite;
|
||||
const char *b = buf;
|
||||
|
||||
for (nwrite=0 ; nwrite < len ; nwrite++) {
|
||||
BSP_uart_polled_write(uart, *b++);
|
||||
}
|
||||
return nwrite;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
BSP_uart_termios_write_com(int minor, const char *buf, size_t len)
|
||||
{
|
||||
int uart=minor; /* could differ, theoretically */
|
||||
|
||||
if(len <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the TX buffer is busy - something is royally screwed up */
|
||||
/* assert((uread(BSP_UART_COM1, LSR) & THRE) != 0); */
|
||||
|
||||
if(termios_stopped_com[uart])
|
||||
{
|
||||
/* CTS low */
|
||||
termios_tx_hold_com[uart] = *buf;
|
||||
termios_tx_hold_valid_com[uart] = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write character */
|
||||
uwrite(uart, THR, *buf & 0xff);
|
||||
|
||||
/* Enable interrupts if necessary */
|
||||
if(!termios_tx_active_com[uart] && uart_data[uart].hwFlow)
|
||||
{
|
||||
termios_tx_active_com[uart] = 1;
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
TRANSMIT_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE |
|
||||
MODEM_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
else if(!termios_tx_active_com[uart])
|
||||
{
|
||||
termios_tx_active_com[uart] = 1;
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
TRANSMIT_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
BSP_uart_termios_read_com(int uart)
|
||||
{
|
||||
int off = (int)0;
|
||||
char buf[40];
|
||||
rtems_interrupt_level l;
|
||||
|
||||
/* read bytes */
|
||||
while (( off < sizeof(buf) ) && ( uread(uart, LSR) & DR )) {
|
||||
buf[off++] = uread(uart, RBR);
|
||||
}
|
||||
|
||||
/* write out data */
|
||||
if ( off > 0 ) {
|
||||
rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart], buf, off);
|
||||
}
|
||||
|
||||
/* enable receive interrupts */
|
||||
rtems_interrupt_disable(l);
|
||||
uwrite(uart, IER, uread(uart, IER) | (RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE));
|
||||
rtems_interrupt_enable(l);
|
||||
|
||||
return ( EOF );
|
||||
}
|
||||
|
||||
static void
|
||||
BSP_uart_termios_isr_com(int uart)
|
||||
{
|
||||
unsigned char buf[40];
|
||||
unsigned char val, ier;
|
||||
int off, ret, vect;
|
||||
|
||||
off = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
vect = uread(uart, IIR) & 0xf;
|
||||
|
||||
switch(vect)
|
||||
{
|
||||
case MODEM_STATUS :
|
||||
val = uread(uart, MSR);
|
||||
if(uart_data[uart].hwFlow)
|
||||
{
|
||||
if(val & CTS)
|
||||
{
|
||||
/* CTS high */
|
||||
termios_stopped_com[uart] = 0;
|
||||
if(termios_tx_hold_valid_com[uart])
|
||||
{
|
||||
termios_tx_hold_valid_com[uart] = 0;
|
||||
BSP_uart_termios_write_com(uart, &termios_tx_hold_com[uart],
|
||||
1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* CTS low */
|
||||
termios_stopped_com[uart] = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NO_MORE_INTR :
|
||||
/* No more interrupts */
|
||||
if(off != 0)
|
||||
{
|
||||
/* Update rx buffer */
|
||||
rtems_termios_enqueue_raw_characters(termios_ttyp_com[uart],
|
||||
(char *)buf,
|
||||
off);
|
||||
}
|
||||
return;
|
||||
case TRANSMITTER_HODING_REGISTER_EMPTY :
|
||||
/*
|
||||
* TX holding empty: we have to disable these interrupts
|
||||
* if there is nothing more to send.
|
||||
*/
|
||||
|
||||
ret = rtems_termios_dequeue_characters(termios_ttyp_com[uart], 1);
|
||||
|
||||
/* If nothing else to send disable interrupts */
|
||||
if(ret == 0 && uart_data[uart].hwFlow)
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE |
|
||||
MODEM_ENABLE
|
||||
)
|
||||
);
|
||||
termios_tx_active_com[uart] = 0;
|
||||
}
|
||||
else if(ret == 0)
|
||||
{
|
||||
uwrite(uart, IER,
|
||||
(RECEIVE_ENABLE |
|
||||
RECEIVER_LINE_ST_ENABLE
|
||||
)
|
||||
);
|
||||
termios_tx_active_com[uart] = 0;
|
||||
}
|
||||
break;
|
||||
case RECEIVER_DATA_AVAIL :
|
||||
case CHARACTER_TIMEOUT_INDICATION:
|
||||
if ( uart_data[uart].ioMode == TERMIOS_TASK_DRIVEN )
|
||||
{
|
||||
/* ensure interrupts are enabled */
|
||||
if ( (ier = uread(uart,IER)) & RECEIVE_ENABLE )
|
||||
{
|
||||
/* disable interrupts and notify termios */
|
||||
ier &= ~(RECEIVE_ENABLE | RECEIVER_LINE_ST_ENABLE);
|
||||
uwrite(uart, IER, ier);
|
||||
rtems_termios_rxirq_occured(termios_ttyp_com[uart]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* RX data ready */
|
||||
assert(off < sizeof(buf));
|
||||
while ( off < sizeof(buf) && ( DR & uread(uart, LSR) ) )
|
||||
buf[off++] = uread(uart, RBR);
|
||||
}
|
||||
break;
|
||||
case RECEIVER_ERROR:
|
||||
/* RX error: eat character */
|
||||
uartError(uart, termios_ttyp_com[uart]);
|
||||
break;
|
||||
default:
|
||||
/* Should not happen */
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - Note that this can now be one isr with the uart
|
||||
* passed as the parameter.
|
||||
*/
|
||||
void
|
||||
BSP_uart_termios_isr_com1(void *unused)
|
||||
{
|
||||
BSP_uart_termios_isr_com(BSP_UART_COM1);
|
||||
}
|
||||
|
||||
void
|
||||
BSP_uart_termios_isr_com2(void *unused)
|
||||
{
|
||||
BSP_uart_termios_isr_com(BSP_UART_COM2);
|
||||
}
|
||||
|
||||
/* retrieve 'break' handler info */
|
||||
int
|
||||
BSP_uart_get_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
|
||||
{
|
||||
BSP_UartBreakCb cb=arg->buffer;
|
||||
unsigned long flags;
|
||||
SANITY_CHECK(uart);
|
||||
rtems_interrupt_disable(flags);
|
||||
*cb = uart_data[uart].breakCallback;
|
||||
rtems_interrupt_enable(flags);
|
||||
arg->ioctl_return=0;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/* install 'break' handler */
|
||||
int
|
||||
BSP_uart_set_break_cb(int uart, rtems_libio_ioctl_args_t *arg)
|
||||
{
|
||||
BSP_UartBreakCb cb=arg->buffer;
|
||||
unsigned long flags;
|
||||
SANITY_CHECK(uart);
|
||||
rtems_interrupt_disable(flags);
|
||||
uart_data[uart].breakCallback = *cb;
|
||||
rtems_interrupt_enable(flags);
|
||||
arg->ioctl_return=0;
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
371
bsps/powerpc/ss555/console/console.c
Normal file
371
bsps/powerpc/ss555/console/console.c
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* console.c
|
||||
*
|
||||
* This file contains the Intec SS555 termios serial I/O package.
|
||||
*
|
||||
* The SCI channels are assigned as follows
|
||||
*
|
||||
* Channel Device Minor
|
||||
* SCI1 /dev/tty0 0
|
||||
* SCI2 /dev/tty1 1
|
||||
*
|
||||
* All ports support termios. The use of termios is recommended for real-time
|
||||
* applications. Termios provides buffering and input processing. When not
|
||||
* using termios, processing is limited to the substitution of LF for CR on
|
||||
* input, and the output of a CR following the output of a LF character.
|
||||
* Note that the terminal should not send CR/LF pairs when the return key
|
||||
* is pressed, and that output lines are terminated with LF/CR, not CR/LF
|
||||
* (although that would be easy to change).
|
||||
*
|
||||
* I/O may be interrupt-driven (recommended for real-time applications) or
|
||||
* polled.
|
||||
*
|
||||
* LIMITATIONS:
|
||||
*
|
||||
* It is not possible to use different I/O modes on the different ports. The
|
||||
* exception is with printk. The printk port can use a different mode from
|
||||
* the other ports. If this is done, it is important not to open the printk
|
||||
* port from an RTEMS application.
|
||||
*
|
||||
* Currently, the I/O modes are determined at build time. It would be much
|
||||
* better to have the mode selected at boot time based on parameters in
|
||||
* NVRAM.
|
||||
*
|
||||
* Interrupt-driven I/O requires termios.
|
||||
*
|
||||
* TESTS:
|
||||
*
|
||||
* TO RUN THE TESTS, USE POLLED I/O WITHOUT TERMIOS SUPPORT. Some tests
|
||||
* play with the interrupt masks and turn off I/O. Those tests will hang
|
||||
* when interrupt-driven I/O is used. Other tests, such as cdtest, do I/O
|
||||
* from the static constructors before the console is open. This test
|
||||
* will not work with interrupt-driven I/O. Because of the buffering
|
||||
* performed in termios, test output may not be in sequence.The tests
|
||||
* should all be fixed to work with interrupt-driven I/O and to
|
||||
* produce output in the expected sequence. Obviously, the termios test
|
||||
* requires termios support in the driver.
|
||||
*
|
||||
* Set CONSOLE_MINOR to the appropriate device minor number in the
|
||||
* config file. This allows the RTEMS application console to be different
|
||||
* from the GDB port.
|
||||
*
|
||||
* This driver handles both available serial ports: it distinguishes
|
||||
* the sub-devices using minor device numbers. It is not possible to have
|
||||
* other protocols running on the other ports when this driver is used as
|
||||
* currently written.
|
||||
*
|
||||
*
|
||||
* SS555 port sponsored by Defence Research and Development Canada - Suffield
|
||||
* Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
|
||||
*
|
||||
* Derived from c/src/lib/libbsp/powerpc/mbx8xx/console/console.c:
|
||||
*
|
||||
* Based on code (alloc860.c in eth_comm port) by
|
||||
* Jay Monkman (jmonkman@frasca.com),
|
||||
* Copyright (C) 1998 by Frasca International, Inc.
|
||||
*
|
||||
* Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca>
|
||||
* and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca>.
|
||||
* Copyright (c) 2000, National Research Council of Canada
|
||||
*
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/libio.h>
|
||||
#include <bsp.h> /* Must be before libio.h */
|
||||
|
||||
static void _BSP_output_char( char c );
|
||||
static rtems_status_code do_poll_read( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
|
||||
static rtems_status_code do_poll_write( rtems_device_major_number major, rtems_device_minor_number minor, void * arg);
|
||||
|
||||
static void _BSP_null_char( char c ) {return;}
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = _BSP_null_char;
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
|
||||
/*
|
||||
* do_poll_read
|
||||
*
|
||||
* Input characters through polled I/O. Returns as soon as a character has
|
||||
* been received. Otherwise, if we wait for the number of requested
|
||||
* characters, we could be here forever!
|
||||
*
|
||||
* CR is converted to LF on input. The terminal should not send a CR/LF pair
|
||||
* when the return or enter key is pressed.
|
||||
*
|
||||
* Input parameters:
|
||||
* major - ignored. Should be the major number for this driver.
|
||||
* minor - selected channel.
|
||||
* arg->buffer - where to put the received characters.
|
||||
* arg->count - number of characters to receive before returning--Ignored.
|
||||
*
|
||||
* Output parameters:
|
||||
* arg->bytes_moved - the number of characters read. Always 1.
|
||||
*
|
||||
* Return value: RTEMS_SUCCESSFUL
|
||||
*
|
||||
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
|
||||
*/
|
||||
static rtems_status_code do_poll_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void * arg
|
||||
)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = arg;
|
||||
int c;
|
||||
|
||||
while( (c = m5xx_uart_pollRead(minor)) == -1 );
|
||||
rw_args->buffer[0] = (uint8_t)c;
|
||||
if( rw_args->buffer[0] == '\r' )
|
||||
rw_args->buffer[0] = '\n';
|
||||
rw_args->bytes_moved = 1;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_poll_write
|
||||
*
|
||||
* Output characters through polled I/O. Returns only once every character has
|
||||
* been sent.
|
||||
*
|
||||
* CR is transmitted AFTER a LF on output.
|
||||
*
|
||||
* Input parameters:
|
||||
* major - ignored. Should be the major number for this driver.
|
||||
* minor - selected channel
|
||||
* arg->buffer - where to get the characters to transmit.
|
||||
* arg->count - the number of characters to transmit before returning.
|
||||
*
|
||||
* Output parameters:
|
||||
* arg->bytes_moved - the number of characters read
|
||||
*
|
||||
* Return value: RTEMS_SUCCESSFUL
|
||||
*
|
||||
* CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
|
||||
*/
|
||||
static rtems_status_code do_poll_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void * arg
|
||||
)
|
||||
{
|
||||
rtems_libio_rw_args_t *rw_args = arg;
|
||||
uint32_t i;
|
||||
char cr ='\r';
|
||||
|
||||
for( i = 0; i < rw_args->count; i++ ) {
|
||||
m5xx_uart_pollWrite(minor, &(rw_args->buffer[i]), 1);
|
||||
if ( rw_args->buffer[i] == '\n' )
|
||||
m5xx_uart_pollWrite(minor, &cr, 1);
|
||||
}
|
||||
rw_args->bytes_moved = i;
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print functions prototyped in bspIo.h
|
||||
*/
|
||||
|
||||
static void _BSP_output_char( char c )
|
||||
{
|
||||
char cr = '\r';
|
||||
|
||||
/*
|
||||
* Can't rely on console_initialize having been called before this
|
||||
* function is used, so it may fail.
|
||||
*/
|
||||
|
||||
m5xx_uart_pollWrite( PRINTK_MINOR, &c, 1 );
|
||||
if( c == '\n' )
|
||||
m5xx_uart_pollWrite( PRINTK_MINOR, &cr, 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
***************
|
||||
* BOILERPLATE *
|
||||
***************
|
||||
*
|
||||
* All these functions are prototyped in rtems/c/src/lib/include/console.h.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initialize and register the device
|
||||
*/
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code status;
|
||||
|
||||
/*
|
||||
* Set up TERMIOS if needed
|
||||
*/
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
rtems_termios_initialize ();
|
||||
#endif /* UARTS_USE_TERMIOS */
|
||||
|
||||
/*
|
||||
* Do device-specific initialization
|
||||
*/
|
||||
BSP_output_char = _BSP_output_char;
|
||||
|
||||
m5xx_uart_initialize(SCI1_MINOR);
|
||||
status = rtems_io_register_name ("/dev/tty0", major, SCI1_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
m5xx_uart_initialize(SCI2_MINOR);
|
||||
status = rtems_io_register_name ("/dev/tty1", major, SCI2_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
/* Now register the RTEMS console */
|
||||
status = rtems_io_register_name ("/dev/console", major, CONSOLE_MINOR);
|
||||
if (status != RTEMS_SUCCESSFUL)
|
||||
rtems_fatal_error_occurred (status);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open the device
|
||||
*/
|
||||
rtems_device_driver console_open(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
if ( minor > NUM_PORTS - 1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if (UARTS_USE_TERMIOS == 1)
|
||||
{
|
||||
#if (UARTS_IO_MODE == 1) /* RTEMS interrupt-driven I/O with termios */
|
||||
|
||||
static const rtems_termios_callbacks callbacks = {
|
||||
m5xx_uart_firstOpen, /* firstOpen */
|
||||
m5xx_uart_lastClose, /* lastClose */
|
||||
NULL, /* pollRead */
|
||||
m5xx_uart_write, /* write */
|
||||
m5xx_uart_setAttributes, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
|
||||
};
|
||||
sc = rtems_termios_open( major, minor, arg, &callbacks );
|
||||
|
||||
#else /* UARTS_IO_MODE != 1 */ /* RTEMS polled I/O with termios */
|
||||
|
||||
static const rtems_termios_callbacks callbacks = {
|
||||
m5xx_uart_firstOpen, /* firstOpen */
|
||||
m5xx_uart_lastClose, /* lastClose */
|
||||
m5xx_uart_pollRead, /* pollRead */
|
||||
m5xx_uart_pollWrite, /* write */
|
||||
m5xx_uart_setAttributes, /* setAttributes */
|
||||
NULL, /* stopRemoteTx */
|
||||
NULL, /* startRemoteTx */
|
||||
TERMIOS_POLLED /* outputUsesInterrupts */
|
||||
};
|
||||
sc = rtems_termios_open( major, minor, arg, &callbacks );
|
||||
|
||||
#endif
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
#else /* no termios -- default to polled I/O */
|
||||
{
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close the device
|
||||
*/
|
||||
rtems_device_driver console_close(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_close( arg );
|
||||
#else
|
||||
return RTEMS_SUCCESSFUL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the device
|
||||
*/
|
||||
rtems_device_driver console_read(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_read( arg );
|
||||
#else
|
||||
return do_poll_read( major, minor, arg );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Write to the device
|
||||
*/
|
||||
rtems_device_driver console_write(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_write( arg );
|
||||
#else
|
||||
return do_poll_write( major, minor, arg );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle ioctl request.
|
||||
*/
|
||||
rtems_device_driver console_control(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
if ( minor > NUM_PORTS-1 )
|
||||
return RTEMS_INVALID_NUMBER;
|
||||
|
||||
#if UARTS_USE_TERMIOS == 1
|
||||
return rtems_termios_ioctl( arg );
|
||||
#else
|
||||
return RTEMS_SUCCESSFUL;
|
||||
#endif
|
||||
}
|
||||
128
bsps/powerpc/t32mppc/console/console.c
Normal file
128
bsps/powerpc/t32mppc/console/console.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Console driver for Lauterbach Trace32 Simulator. The implementation is
|
||||
* based on the example in "demo/powerpc/etc/terminal/terminal_mpc85xx.cmm" in
|
||||
* the Trace32 system directory.
|
||||
*/
|
||||
|
||||
#include <rtems/bspIo.h>
|
||||
#include <rtems/console.h>
|
||||
#include <rtems/termiostypes.h>
|
||||
|
||||
volatile unsigned char messagebufferin[256];
|
||||
|
||||
volatile unsigned char messagebufferout[256];
|
||||
|
||||
typedef struct {
|
||||
rtems_termios_device_context base;
|
||||
int input_size;
|
||||
int input_index;
|
||||
} t32_console_context;
|
||||
|
||||
static t32_console_context t32_console_instance;
|
||||
|
||||
static bool t32_console_first_open(
|
||||
rtems_termios_tty *tty,
|
||||
rtems_termios_device_context *base,
|
||||
struct termios *term,
|
||||
rtems_libio_open_close_args_t *args
|
||||
)
|
||||
{
|
||||
rtems_termios_set_initial_baud(tty, 115200);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int t32_console_read_polled(rtems_termios_device_context *base)
|
||||
{
|
||||
t32_console_context *ctx = (t32_console_context *) base;
|
||||
int c;
|
||||
|
||||
if (ctx->input_size == 0) {
|
||||
int new_bufsize = messagebufferin[0];
|
||||
|
||||
if (new_bufsize != 0) {
|
||||
ctx->input_size = new_bufsize;
|
||||
ctx->input_index = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
c = messagebufferin[4 + ctx->input_index];
|
||||
|
||||
++ctx->input_index;
|
||||
if (ctx->input_index >= ctx->input_size) {
|
||||
messagebufferin[0] = 0;
|
||||
ctx->input_size = 0;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void t32_console_write_char_polled(char c)
|
||||
{
|
||||
while (messagebufferout[0] != 0) {
|
||||
/* Wait for ready */
|
||||
}
|
||||
|
||||
messagebufferout[4] = (unsigned char) c;
|
||||
messagebufferout[0] = 1;
|
||||
}
|
||||
|
||||
static void t32_console_write_polled(
|
||||
rtems_termios_device_context *base,
|
||||
const char *s,
|
||||
size_t n
|
||||
)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
t32_console_write_char_polled(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const rtems_termios_device_handler t32_console_handler = {
|
||||
.first_open = t32_console_first_open,
|
||||
.poll_read = t32_console_read_polled,
|
||||
.write = t32_console_write_polled,
|
||||
.mode = TERMIOS_POLLED
|
||||
};
|
||||
|
||||
rtems_device_driver console_initialize(
|
||||
rtems_device_major_number major,
|
||||
rtems_device_minor_number minor,
|
||||
void *arg
|
||||
)
|
||||
{
|
||||
t32_console_context *ctx = &t32_console_instance;
|
||||
|
||||
rtems_termios_initialize();
|
||||
rtems_termios_device_context_initialize(&ctx->base, "T32 Console");
|
||||
rtems_termios_device_install(
|
||||
CONSOLE_DEVICE_NAME,
|
||||
&t32_console_handler,
|
||||
NULL,
|
||||
&ctx->base
|
||||
);
|
||||
|
||||
return RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
BSP_output_char_function_type BSP_output_char = t32_console_write_char_polled;
|
||||
|
||||
BSP_polling_getchar_function_type BSP_poll_char = NULL;
|
||||
1115
bsps/powerpc/tqm8xx/console/console.c
Normal file
1115
bsps/powerpc/tqm8xx/console/console.c
Normal file
File diff suppressed because it is too large
Load Diff
425
bsps/powerpc/virtex/console/consolelite.c
Normal file
425
bsps/powerpc/virtex/console/consolelite.c
Normal file
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user