summaryrefslogtreecommitdiffstats
path: root/bsps/powerpc
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-19 06:28:01 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-04-20 13:08:32 +0200
commitd7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc (patch)
treecaa54b4229e86a68c84ab5961af34e087dce5302 /bsps/powerpc
parentbsps/powerpc: Move shared btimer support (diff)
downloadrtems-d7d66d7d4523b904c8ccc6aea3709dc0d5aa5bdc.tar.bz2
bsps: Move console drivers to bsps
This patch is a part of the BSP source reorganization. Update #3285.
Diffstat (limited to 'bsps/powerpc')
-rw-r--r--bsps/powerpc/gen5200/console/console.c835
-rw-r--r--bsps/powerpc/gen83xx/console/console-config.c107
-rw-r--r--bsps/powerpc/mpc55xxevb/console/console-config.c41
-rw-r--r--bsps/powerpc/mpc55xxevb/console/console-esci.c354
-rw-r--r--bsps/powerpc/mpc55xxevb/console/console-generic.c168
-rw-r--r--bsps/powerpc/mpc55xxevb/console/console-linflex.c417
-rw-r--r--bsps/powerpc/mpc8260ads/console/console.c458
-rw-r--r--bsps/powerpc/psim/console/console-io.c78
-rw-r--r--bsps/powerpc/psim/console/consupp.S33
-rw-r--r--bsps/powerpc/qemuppc/console/console-io.c77
-rw-r--r--bsps/powerpc/qoriq/console/console-config.c330
-rw-r--r--bsps/powerpc/qoriq/console/uart-bridge-master.c181
-rw-r--r--bsps/powerpc/qoriq/console/uart-bridge-slave.c195
-rw-r--r--bsps/powerpc/shared/console/console.c314
-rw-r--r--bsps/powerpc/shared/console/uart.c781
-rw-r--r--bsps/powerpc/ss555/console/console.c371
-rw-r--r--bsps/powerpc/t32mppc/console/console.c128
-rw-r--r--bsps/powerpc/tqm8xx/console/console.c1115
-rw-r--r--bsps/powerpc/virtex/console/consolelite.c425
19 files changed, 6408 insertions, 0 deletions
diff --git a/bsps/powerpc/gen5200/console/console.c b/bsps/powerpc/gen5200/console/console.c
new file mode 100644
index 0000000000..d7325032c4
--- /dev/null
+++ b/bsps/powerpc/gen5200/console/console.c
@@ -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);
+}
diff --git a/bsps/powerpc/gen83xx/console/console-config.c b/bsps/powerpc/gen83xx/console/console-config.c
new file mode 100644
index 0000000000..d0071cd220
--- /dev/null
+++ b/bsps/powerpc/gen83xx/console/console-config.c
@@ -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;
diff --git a/bsps/powerpc/mpc55xxevb/console/console-config.c b/bsps/powerpc/mpc55xxevb/console/console-config.c
new file mode 100644
index 0000000000..d0ea250917
--- /dev/null
+++ b/bsps/powerpc/mpc55xxevb/console/console-config.c
@@ -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);
diff --git a/bsps/powerpc/mpc55xxevb/console/console-esci.c b/bsps/powerpc/mpc55xxevb/console/console-esci.c
new file mode 100644
index 0000000000..9e6646fb65
--- /dev/null
+++ b/bsps/powerpc/mpc55xxevb/console/console-esci.c
@@ -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 */
diff --git a/bsps/powerpc/mpc55xxevb/console/console-generic.c b/bsps/powerpc/mpc55xxevb/console/console-generic.c
new file mode 100644
index 0000000000..71385adf2b
--- /dev/null
+++ b/bsps/powerpc/mpc55xxevb/console/console-generic.c
@@ -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;
diff --git a/bsps/powerpc/mpc55xxevb/console/console-linflex.c b/bsps/powerpc/mpc55xxevb/console/console-linflex.c
new file mode 100644
index 0000000000..02978be524
--- /dev/null
+++ b/bsps/powerpc/mpc55xxevb/console/console-linflex.c
@@ -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 */
diff --git a/bsps/powerpc/mpc8260ads/console/console.c b/bsps/powerpc/mpc8260ads/console/console.c
new file mode 100644
index 0000000000..873c38dc3e
--- /dev/null
+++ b/bsps/powerpc/mpc8260ads/console/console.c
@@ -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
+
+}
diff --git a/bsps/powerpc/psim/console/console-io.c b/bsps/powerpc/psim/console/console-io.c
new file mode 100644
index 0000000000..512b90dde2
--- /dev/null
+++ b/bsps/powerpc/psim/console/console-io.c
@@ -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;
diff --git a/bsps/powerpc/psim/console/consupp.S b/bsps/powerpc/psim/console/consupp.S
new file mode 100644
index 0000000000..bb9e834fc6
--- /dev/null
+++ b/bsps/powerpc/psim/console/consupp.S
@@ -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)
diff --git a/bsps/powerpc/qemuppc/console/console-io.c b/bsps/powerpc/qemuppc/console/console-io.c
new file mode 100644
index 0000000000..738bd27966
--- /dev/null
+++ b/bsps/powerpc/qemuppc/console/console-io.c
@@ -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;
diff --git a/bsps/powerpc/qoriq/console/console-config.c b/bsps/powerpc/qoriq/console/console-config.c
new file mode 100644
index 0000000000..4c1ca1d3f6
--- /dev/null
+++ b/bsps/powerpc/qoriq/console/console-config.c
@@ -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;
diff --git a/bsps/powerpc/qoriq/console/uart-bridge-master.c b/bsps/powerpc/qoriq/console/uart-bridge-master.c
new file mode 100644
index 0000000000..588e0a42ad
--- /dev/null
+++ b/bsps/powerpc/qoriq/console/uart-bridge-master.c
@@ -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
+};
diff --git a/bsps/powerpc/qoriq/console/uart-bridge-slave.c b/bsps/powerpc/qoriq/console/uart-bridge-slave.c
new file mode 100644
index 0000000000..44d4cfb712
--- /dev/null
+++ b/bsps/powerpc/qoriq/console/uart-bridge-slave.c
@@ -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
+};
diff --git a/bsps/powerpc/shared/console/console.c b/bsps/powerpc/shared/console/console.c
new file mode 100644
index 0000000000..f275683cc2
--- /dev/null
+++ b/bsps/powerpc/shared/console/console.c
@@ -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;
+}
diff --git a/bsps/powerpc/shared/console/uart.c b/bsps/powerpc/shared/console/uart.c
new file mode 100644
index 0000000000..62212b98db
--- /dev/null
+++ b/bsps/powerpc/shared/console/uart.c
@@ -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;
+}
diff --git a/bsps/powerpc/ss555/console/console.c b/bsps/powerpc/ss555/console/console.c
new file mode 100644
index 0000000000..e13e4734ea
--- /dev/null
+++ b/bsps/powerpc/ss555/console/console.c
@@ -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
+}
diff --git a/bsps/powerpc/t32mppc/console/console.c b/bsps/powerpc/t32mppc/console/console.c
new file mode 100644
index 0000000000..5fbd648765
--- /dev/null
+++ b/bsps/powerpc/t32mppc/console/console.c
@@ -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;
diff --git a/bsps/powerpc/tqm8xx/console/console.c b/bsps/powerpc/tqm8xx/console/console.c
new file mode 100644
index 0000000000..5a681b19fb
--- /dev/null
+++ b/bsps/powerpc/tqm8xx/console/console.c
@@ -0,0 +1,1115 @@
+/*===============================================================*\
+| Project: RTEMS TQM8xx BSP |
++-----------------------------------------------------------------+
+| This file has been adapted to MPC8xx by |
+| Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> |
+| Copyright (c) 2008 |
+| Embedded Brains GmbH |
+| Obere Lagerstr. 30 |
+| D-82178 Puchheim |
+| Germany |
+| rtems@embedded-brains.de |
+| |
+| See the other copyright notice below for the original parts. |
++-----------------------------------------------------------------+
+| 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 |
+\*===============================================================*/
+/* derived from: */
+/*
+ * SMC1/2 SCC1..4 raw console serial I/O.
+ * adapted to work with up to 4 SCC and 2 SMC
+ *
+ * This driver is an example of `TASK DRIVEN' `POLLING' or `INTERRUPT' I/O.
+ *
+ * To run with interrupt-driven I/O, ensure m8xx_smc1_interrupt
+ * is set before calling the initialization routine.
+ *
+ * Author:
+ * W. Eric Norum
+ * Saskatchewan Accelerator Laboratory
+ * University of Saskatchewan
+ * Saskatoon, Saskatchewan, CANADA
+ * eric@skatter.usask.ca
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <rtems.h>
+#include <rtems/console.h>
+#include <rtems/libio.h>
+#include <rtems/termiostypes.h>
+#include <rtems/bspIo.h>
+#include <rtems/error.h>
+#include <rtems/irq.h>
+
+#include <bsp.h>
+#include <mpc8xx.h>
+#include <bsp/irq.h>
+
+/*
+ * Interrupt-driven input buffer
+ */
+#define RXBUFSIZE 16
+
+#define M8xx_SICR_BRG1 (0)
+#define M8xx_SICR_BRG2 (1)
+#define M8xx_SICR_BRG3 (2)
+#define M8xx_SICR_BRG4 (3)
+
+#define M8xx_SICR_SCCRX_MSK(scc) (( 7) << (((scc))*8+3))
+#define M8xx_SICR_SCCRX(scc,clk) ((clk) << (((scc))*8+3))
+
+#define M8xx_SICR_SCCTX_MSK(scc) (( 7) << (((scc))*8+0))
+#define M8xx_SICR_SCCTX(scc,clk) ((clk) << (((scc))*8+0))
+
+#define M8xx_SIMODE_SMCCS(smc,clk) ((clk) << ((smc)*16+12))
+#define M8xx_SIMODE_SMCCS_MSK(smc) M8xx_SIMODE_SMCCS(smc,7)
+
+#define CONS_CHN_CNT 6
+#define CONS_CHN_SCC1 0
+#define CONS_CHN_SCC2 1
+#define CONS_CHN_SCC3 2
+#define CONS_CHN_SCC4 3
+#define CONS_CHN_SMC1 4
+#define CONS_CHN_SMC2 5
+#define CONS_CHN_NONE -1
+
+/*
+ * possible identifiers for bspopts.h: CONS_SxCy_MODE
+ */
+#define CONS_MODE_UNUSED -1
+#define CONS_MODE_POLLED TERMIOS_POLLED
+#define CONS_MODE_IRQ TERMIOS_IRQ_DRIVEN
+
+#define CHN_IS_SCC(chan) ((chan) < CONS_CHN_SMC1)
+
+#define BRG_CNT 4
+
+#define MAX_IDL_DEFAULT 10
+#define DEVICEPREFIX "tty"
+
+/*
+ * Interrupt-driven callback
+ */
+static int m8xx_scc_mode[CONS_CHN_CNT];
+static void *sccttyp[CONS_CHN_CNT];
+typedef struct m8xx_console_chan_desc_s {
+ bool is_scc; /* true for SCC */
+ struct {
+ volatile m8xxSCCparms_t *sccp;
+ volatile m8xxSMCparms_t *smcp;
+ } parms;
+ struct {
+ volatile m8xxSCCRegisters_t *sccr;
+ volatile m8xxSMCRegisters_t *smcr;
+ } regs;
+ int ivec_src;
+ int cr_chan_code;
+ int brg_used;
+} m8xx_console_chan_desc_t;
+
+m8xx_console_chan_desc_t m8xx_console_chan_desc[CONS_CHN_CNT] = {
+ /* SCC1 */
+ {TRUE,
+ {(m8xxSCCparms_t *)&(m8xx.scc1p),NULL},
+ {&(m8xx.scc1),NULL},
+ BSP_CPM_IRQ_SCC1,
+ M8xx_CR_CHAN_SCC1,
+ -1},
+ /* SCC2 */
+ {TRUE,
+ {&(m8xx.scc2p),NULL},
+ {&(m8xx.scc2),NULL},
+ BSP_CPM_IRQ_SCC2,
+ M8xx_CR_CHAN_SCC2,
+ -1},
+ /* SCC3 */
+ {TRUE,
+ {&(m8xx.scc3p),NULL},
+ {&(m8xx.scc3),NULL},
+ BSP_CPM_IRQ_SCC3,
+ M8xx_CR_CHAN_SCC3,
+ -1},
+ /* SCC4 */
+ {TRUE,
+ {&(m8xx.scc4p),NULL},
+ {&(m8xx.scc4),NULL},
+ BSP_CPM_IRQ_SCC4,
+ M8xx_CR_CHAN_SCC4,
+ -1},
+ /* SMC1 */
+ {FALSE,
+ {NULL,&(m8xx.smc1p)},
+ {NULL,&(m8xx.smc1)},
+ BSP_CPM_IRQ_SMC1,
+ M8xx_CR_CHAN_SMC1,
+ -1},
+ /* SMC2 */
+ {FALSE,
+ {NULL,&(m8xx.smc2p)},
+ {NULL,&(m8xx.smc2)},
+ BSP_CPM_IRQ_SMC2_OR_PIP,
+ M8xx_CR_CHAN_SMC2,
+ -1}};
+
+#define CHN_PARAM_GET(chan,param) \
+ (m8xx_console_chan_desc[chan].is_scc \
+ ? m8xx_console_chan_desc[chan].parms.sccp->param \
+ : m8xx_console_chan_desc[chan].parms.smcp->param)
+
+#define CHN_PARAM_SET(chan,param,value) \
+ do {if (m8xx_console_chan_desc[chan].is_scc) \
+ m8xx_console_chan_desc[chan].parms.sccp->param = value; \
+ else \
+ m8xx_console_chan_desc[chan].parms.smcp->param = value; \
+ } while (0)
+
+#define CHN_EVENT_GET(chan) \
+ (m8xx_console_chan_desc[chan].is_scc \
+ ? m8xx_console_chan_desc[chan].regs.sccr->scce \
+ : m8xx_console_chan_desc[chan].regs.smcr->smce)
+
+#define CHN_EVENT_CLR(chan,mask) \
+ do { \
+ if (m8xx_console_chan_desc[chan].is_scc) \
+ m8xx_console_chan_desc[chan].regs.sccr->scce = (mask); \
+ else \
+ m8xx_console_chan_desc[chan].regs.smcr->smce = (mask); \
+ }while (0)
+
+#define CHN_MASK_GET(chan) \
+ (m8xx_console_chan_desc[chan].is_scc \
+ ? m8xx_console_chan_desc[chan].regs.sccr->sccm \
+ : m8xx_console_chan_desc[chan].regs.smcr->smcm)
+
+#define CHN_MASK_SET(chan,mask) \
+ do { \
+ if (m8xx_console_chan_desc[chan].is_scc) \
+ m8xx_console_chan_desc[chan].regs.sccr->sccm = (mask); \
+ else \
+ m8xx_console_chan_desc[chan].regs.smcr->smcm = (mask); \
+ }while (0)
+
+
+/*
+ * I/O buffers and pointers to buffer descriptors
+ */
+#define SCC_RXBD_CNT 4
+#define SCC_TXBD_CNT 4
+typedef volatile char sccRxBuf_t[SCC_RXBD_CNT][RXBUFSIZE];
+static sccRxBuf_t *rxBuf[CONS_CHN_CNT];
+
+static volatile m8xxBufferDescriptor_t *sccFrstRxBd[CONS_CHN_CNT];
+static volatile m8xxBufferDescriptor_t *sccCurrRxBd[CONS_CHN_CNT];
+static volatile m8xxBufferDescriptor_t *sccFrstTxBd[CONS_CHN_CNT];
+static volatile m8xxBufferDescriptor_t *sccPrepTxBd[CONS_CHN_CNT];
+static volatile m8xxBufferDescriptor_t *sccDequTxBd[CONS_CHN_CNT];
+
+/*
+ * Compute baud-rate-generator configuration register value
+ */
+static uint32_t
+sccBRGval (int baud)
+{
+ int divisor;
+ int div16 = 0;
+
+ divisor = ((BSP_bus_frequency / 16) + (baud / 2)) / baud;
+ if (divisor > 4096) {
+ div16 = 1;
+ divisor = (divisor + 8) / 16;
+ }
+ return M8xx_BRG_EN | M8xx_BRG_EXTC_BRGCLK | ((divisor - 1) << 1) | div16;
+}
+
+typedef struct {
+ uint32_t reg_content;
+ int link_cnt;
+}brg_state_t;
+brg_state_t scc_brg_state[BRG_CNT];
+
+/*
+ * initialize brg_state
+ */
+static void sccBRGinit(void)
+{
+ int brg_idx;
+
+ for (brg_idx = 0;brg_idx < BRG_CNT;brg_idx++) {
+ scc_brg_state[brg_idx].reg_content = 0;
+ scc_brg_state[brg_idx].link_cnt = 0;
+ }
+#ifndef MDE360
+ /*
+ * on ZEM40, init CLK4/5 inputs
+ */
+ m8xx.papar |= ((1 << 11) | (1 << 12));
+ m8xx.padir &= ~((1 << 11) | (1 << 12));
+#endif
+}
+
+#if CONS_USE_EXT_CLK
+/*
+ * input clock frq for CPM clock inputs
+ */
+static uint32_t clkin_frq[2][4] = {
+#ifdef MDE360
+ {0,0,0,0},
+ {0,0,0,0}
+#else
+ {0,0,0,1843000},
+ {1843000,0,0,0}
+#endif
+};
+#endif
+
+/*
+ * allocate, set and connect baud rate generators
+ * FIXME: or clock input
+ * FIXME: set pin to be clock input
+ */
+
+static int sccBRGalloc(int chan,int baud)
+{
+ rtems_interrupt_level level;
+ m8xx_console_chan_desc_t *chan_desc = &(m8xx_console_chan_desc[chan]);
+ uint32_t reg_val;
+ int old_brg;
+ int new_brg = -1;
+ int brg_idx;
+#if CONS_USE_EXT_CLK
+ int clk_group;
+ int clk_sel;
+#endif
+
+ old_brg = chan_desc->brg_used;
+ /* compute brg register contents needed */
+ reg_val = sccBRGval(baud);
+
+#if CONS_EXT_CLK
+ /* search for clock input with this frq */
+ clk_group = ((chan == CONS_CHN_SCC3) ||
+ (chan == CONS_CHN_SCC4) ||
+ (chan == CONS_CHN_SMC2)) ? 1 : 0;
+
+ for (clk_sel = 0, new_brg = -1;
+ (clk_sel < 4) && (new_brg < 0);
+ clk_sel++) {
+ if (baud == (clkin_frq[clk_group][clk_sel] / 16)) {
+ new_brg = clk_sel + 4;
+ }
+ }
+#endif
+
+ rtems_interrupt_disable(level);
+
+ if (new_brg < 0) {
+ /* search for brg with this settings */
+ for (brg_idx = 0;
+ (new_brg < 0) && (brg_idx < BRG_CNT);
+ brg_idx++) {
+ if (scc_brg_state[brg_idx].reg_content == reg_val) {
+ new_brg = brg_idx;
+ }
+ }
+ /*
+ * if not found: check, whether brg currently in use
+ * is linked only from our channel
+ */
+ if ((new_brg < 0) &&
+ (old_brg >= 0) &&
+ (scc_brg_state[old_brg].link_cnt == 1)) {
+ new_brg = old_brg;
+ }
+ /* if not found: search for unused brg, set it */
+ for (brg_idx = 0;
+ (new_brg < 0) && (brg_idx < BRG_CNT);
+ brg_idx++) {
+ if (scc_brg_state[brg_idx].link_cnt == 0) {
+ new_brg = brg_idx;
+ }
+ }
+ }
+
+ /* decrease old link count */
+ if ((old_brg >= 0) &&
+ (old_brg < 4)) {
+ scc_brg_state[old_brg].link_cnt--;
+ }
+ /* increase new brg link count, set brg */
+ if ((new_brg >= 0) &&
+ (new_brg < 4)) {
+ scc_brg_state[new_brg].link_cnt++;
+ scc_brg_state[new_brg].reg_content = reg_val;
+ (&m8xx.brgc1)[new_brg] = reg_val;
+ }
+ rtems_interrupt_enable(level);
+
+ /* connect to scc/smc */
+ if (new_brg >= 0) {
+ m8xx_console_chan_desc[chan].brg_used = new_brg;
+ /*
+ * Put SCC in NMSI mode, connect SCC to BRG or CLKx
+ */
+ if (m8xx_console_chan_desc[chan].is_scc) {
+ m8xx.sicr = ((m8xx.sicr & ~(M8xx_SICR_SCCRX_MSK(chan) |
+ M8xx_SICR_SCCTX_MSK(chan))) |
+ M8xx_SICR_SCCRX(chan,new_brg)|
+ M8xx_SICR_SCCTX(chan,new_brg));
+ }
+ else {
+ /* connect SMC to BRGx or CLKx... */
+ m8xx.simode = ((m8xx.simode & ~(M8xx_SIMODE_SMCCS_MSK(chan - CONS_CHN_SMC1)))|
+ M8xx_SIMODE_SMCCS(chan - CONS_CHN_SMC1,new_brg));
+ }
+ }
+ return (new_brg < 0);
+}
+
+
+/*
+ * Hardware-dependent portion of tcsetattr().
+ */
+static int
+sccSetAttributes (int minor, const struct termios *t)
+{
+ int baud;
+
+ switch (t->c_ospeed) {
+ default: baud = -1; break;
+ case B50: baud = 50; break;
+ case B75: baud = 75; break;
+ case B110: baud = 110; break;
+ case B134: baud = 134; break;
+ case B150: baud = 150; break;
+ case B200: baud = 200; break;
+ case B300: baud = 300; break;
+ case B600: baud = 600; break;
+ case B1200: baud = 1200; break;
+ case B1800: baud = 1800; break;
+ case B2400: baud = 2400; break;
+ case B4800: baud = 4800; break;
+ case B9600: baud = 9600; break;
+ case B19200: baud = 19200; break;
+ case B38400: baud = 38400; break;
+ case B57600: baud = 57600; break;
+ case B115200: baud = 115200; break;
+ case B230400: baud = 230400; break;
+ case B460800: baud = 460800; break;
+ }
+ return sccBRGalloc(minor,baud);
+ return 0;
+}
+
+/*
+ * Interrupt handler
+ */
+static rtems_isr
+sccInterruptHandler (void *arg)
+{
+ int chan = (int)arg;
+
+ /*
+ * Buffer received?
+ */
+ if (CHN_EVENT_GET(chan) & 0x1) {
+ /*
+ * clear SCC event flag
+ */
+ CHN_EVENT_CLR(chan,0x01);
+ /*
+ * process event
+ */
+ while ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) == 0) {
+ if (sccttyp[chan] != NULL) {
+ rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer,
+ sccCurrRxBd[chan]->length);
+ rtems_termios_enqueue_raw_characters (sccttyp[chan],
+ (char *)sccCurrRxBd[chan]->buffer,
+ sccCurrRxBd[chan]->length);
+ }
+ /*
+ * clear status
+ */
+ sccCurrRxBd[chan]->status =
+ (sccCurrRxBd[chan]->status
+ & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
+ | M8xx_BD_EMPTY;
+ /*
+ * advance to next BD
+ */
+ if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) {
+ sccCurrRxBd[chan] = sccFrstRxBd[chan];
+ }
+ else {
+ sccCurrRxBd[chan]++;
+ }
+ }
+ }
+ /*
+ * Buffer transmitted?
+ */
+ if (CHN_EVENT_GET(chan) & 0x2) {
+ /*
+ * then clear interrupt event bit
+ */
+ CHN_EVENT_CLR(chan,0x2);
+ /*
+ * and signal successful transmit to termios
+ */
+ /*
+ * FIXME: multiple dequeue calls for multiple buffers
+ */
+ while((sccDequTxBd[chan] != sccPrepTxBd[chan]) &&
+ ((sccDequTxBd[chan]->status & M8xx_BD_READY) == 0)) {
+ if (sccttyp[chan] != NULL) {
+ rtems_termios_dequeue_characters (sccttyp[chan],
+ sccDequTxBd[chan]->length);
+ }
+ /*
+ * advance to next BD
+ */
+ if ((sccDequTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
+ sccDequTxBd[chan] = sccFrstTxBd[chan];
+ }
+ else {
+ sccDequTxBd[chan]++;
+ }
+ }
+ }
+}
+
+static void
+mpc8xx_console_irq_on(const rtems_irq_connect_data *irq)
+{
+ CHN_MASK_SET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET,
+ 3); /* Enable TX and RX interrupts */
+}
+
+static void
+mpc8xx_console_irq_off(const rtems_irq_connect_data *irq)
+{
+ CHN_MASK_SET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET,
+ 0); /* Disable TX and RX interrupts */
+}
+
+static int
+mpc8xx_console_irq_isOn(const rtems_irq_connect_data *irq)
+{
+ return (0 != CHN_MASK_GET(irq->name - BSP_CPM_IRQ_LOWEST_OFFSET)); /* Check TX and RX interrupts */
+}
+
+static void
+sccInitialize (int chan)
+{
+ int i;
+ /*
+ * allocate buffers
+ * FIXME: use a cache-line size boundary alloc here
+ */
+ rxBuf[chan] = malloc(sizeof(*rxBuf[chan]) + 2*PPC_CACHE_ALIGNMENT);
+ if (rxBuf[chan] == NULL) {
+ rtems_panic("Cannot allocate console rx buffer\n");
+ }
+ else {
+ /*
+ * round up rxBuf[chan] to start at a cache line size
+ */
+ rxBuf[chan] = (sccRxBuf_t *)
+ (((uint32_t)rxBuf[chan]) +
+ (PPC_CACHE_ALIGNMENT
+ - ((uint32_t)rxBuf[chan]) % PPC_CACHE_ALIGNMENT));
+ }
+ /*
+ * Allocate buffer descriptors
+ */
+ sccCurrRxBd[chan] =
+ sccFrstRxBd[chan] = m8xx_bd_allocate(SCC_RXBD_CNT);
+ sccPrepTxBd[chan] =
+ sccDequTxBd[chan] =
+ sccFrstTxBd[chan] = m8xx_bd_allocate(SCC_TXBD_CNT);
+ switch(chan) {
+ case CONS_CHN_SCC1:
+ /*
+ * Configure port A pins to enable TXD1 and RXD1 pins
+ * FIXME: add setup for modem control lines....
+ */
+ m8xx.papar |= 0x03;
+ m8xx.padir &= ~0x03;
+
+ /*
+ * Configure port C pins to enable RTS1 pins (static active low)
+ */
+ m8xx.pcpar &= ~0x01;
+ m8xx.pcso &= ~0x01;
+ m8xx.pcdir |= 0x01;
+ m8xx.pcdat &= ~0x01;
+ break;
+ case CONS_CHN_SCC2:
+ /*
+ * Configure port A pins to enable TXD2 and RXD2 pins
+ * FIXME: add setup for modem control lines....
+ */
+ m8xx.papar |= 0x0C;
+ m8xx.padir &= ~0x0C;
+
+ /*
+ * Configure port C pins to enable RTS2 pins (static active low)
+ */
+ m8xx.pcpar &= ~0x02;
+ m8xx.pcso &= ~0x02;
+ m8xx.pcdir |= 0x02;
+ m8xx.pcdat &= ~0x02;
+ break;
+ case CONS_CHN_SCC3:
+ /*
+ * Configure port A pins to enable TXD3 and RXD3 pins
+ * FIXME: add setup for modem control lines....
+ */
+ m8xx.papar |= 0x30;
+ m8xx.padir &= ~0x30;
+
+ /*
+ * Configure port C pins to enable RTS3 (static active low)
+ */
+ m8xx.pcpar &= ~0x04;
+ m8xx.pcso &= ~0x04;
+ m8xx.pcdir |= 0x04;
+ m8xx.pcdat &= ~0x04;
+ break;
+ case CONS_CHN_SCC4:
+ /*
+ * Configure port A pins to enable TXD4 and RXD4 pins
+ * FIXME: add setup for modem control lines....
+ */
+ m8xx.papar |= 0xC0;
+ m8xx.padir &= ~0xC0;
+
+ /*
+ * Configure port C pins to enable RTS4 pins (static active low)
+ */
+ m8xx.pcpar &= ~0x08;
+ m8xx.pcso &= ~0x08;
+ m8xx.pcdir |= 0x08;
+ m8xx.pcdat &= ~0x08;
+ break;
+ case CONS_CHN_SMC1:
+ /*
+ * Configure port B pins to enable SMTXD1 and SMRXD1 pins
+ */
+ m8xx.pbpar |= 0xC0;
+ m8xx.pbdir &= ~0xC0;
+ break;
+ case CONS_CHN_SMC2:
+ /*
+ * Configure port B pins to enable SMTXD2 and SMRXD2 pins
+ */
+ m8xx.pbpar |= 0xC00;
+ m8xx.pbdir &= ~0xC00;
+ break;
+ }
+ /*
+ * allocate and connect BRG
+ */
+ sccBRGalloc(chan,9600);
+
+
+ /*
+ * Set up SCCx parameter RAM common to all protocols
+ */
+ CHN_PARAM_SET(chan,rbase,(char *)sccFrstRxBd[chan] - (char *)&m8xx);
+ CHN_PARAM_SET(chan,tbase,(char *)sccFrstTxBd[chan] - (char *)&m8xx);
+ CHN_PARAM_SET(chan,rfcr ,M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0));
+ CHN_PARAM_SET(chan,tfcr ,M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0));
+ if (m8xx_scc_mode[chan] != TERMIOS_POLLED)
+ CHN_PARAM_SET(chan,mrblr,RXBUFSIZE);
+ else
+ CHN_PARAM_SET(chan,mrblr,1);
+
+ /*
+ * Set up SCCx parameter RAM UART-specific parameters
+ */
+ CHN_PARAM_SET(chan,un.uart.max_idl ,MAX_IDL_DEFAULT);
+ CHN_PARAM_SET(chan,un.uart.brkln ,0);
+ CHN_PARAM_SET(chan,un.uart.brkec ,0);
+ CHN_PARAM_SET(chan,un.uart.brkcr ,0);
+ if (m8xx_console_chan_desc[chan].is_scc) {
+ m8xx_console_chan_desc[chan].parms.sccp->un.uart.character[0]=0x8000; /* no char filter */
+ m8xx_console_chan_desc[chan].parms.sccp->un.uart.rccm=0x80FF; /* control character mask */
+ }
+
+ /*
+ * Set up the Receive Buffer Descriptors
+ */
+ for (i = 0;i < SCC_RXBD_CNT;i++) {
+ sccFrstRxBd[chan][i].status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT;
+ if (i == SCC_RXBD_CNT-1) {
+ sccFrstRxBd[chan][i].status |= M8xx_BD_WRAP;
+ }
+ sccFrstRxBd[chan][i].length = 0;
+ sccFrstRxBd[chan][i].buffer = (*rxBuf[chan])[i];
+ }
+ /*
+ * Setup the Transmit Buffer Descriptor
+ */
+ for (i = 0;i < SCC_TXBD_CNT;i++) {
+ sccFrstTxBd[chan][i].status = M8xx_BD_INTERRUPT;
+ if (i == SCC_TXBD_CNT-1) {
+ sccFrstTxBd[chan][i].status |= M8xx_BD_WRAP;
+ }
+ sccFrstTxBd[chan][i].length = 0;
+ sccFrstTxBd[chan][i].buffer = NULL;
+ }
+
+ /*
+ * Set up SCC general and protocol-specific mode registers
+ */
+ CHN_EVENT_CLR(chan,~0); /* Clear any pending events */
+ CHN_MASK_SET(chan,0); /* Mask all interrupt/event sources */
+
+ if (m8xx_console_chan_desc[chan].is_scc) {
+ m8xx_console_chan_desc[chan].regs.sccr->psmr = 0xb000; /* 8N1, CTS flow control */
+ m8xx_console_chan_desc[chan].regs.sccr->gsmr_h = 0x00000000;
+ m8xx_console_chan_desc[chan].regs.sccr->gsmr_l = 0x00028004; /* UART mode */
+ }
+ else {
+ m8xx_console_chan_desc[chan].regs.smcr->smcmr = 0x4820;
+ }
+ /*
+ * Send "Init parameters" command
+ */
+ m8xx_cp_execute_cmd(M8xx_CR_OP_INIT_RX_TX
+ | m8xx_console_chan_desc[chan].cr_chan_code);
+
+ /*
+ * Enable receiver and transmitter
+ */
+ if (m8xx_console_chan_desc[chan].is_scc) {
+ m8xx_console_chan_desc[chan].regs.sccr->gsmr_l |= 0x00000030;
+ }
+ else {
+ m8xx_console_chan_desc[chan].regs.smcr->smcmr |= 0x0003;
+ }
+
+ if (m8xx_scc_mode[chan] != TERMIOS_POLLED) {
+
+ rtems_irq_connect_data irq_conn_data = {
+ m8xx_console_chan_desc[chan].ivec_src,
+ sccInterruptHandler, /* rtems_irq_hdl */
+ (rtems_irq_hdl_param)chan, /* (rtems_irq_hdl_param) */
+ mpc8xx_console_irq_on, /* (rtems_irq_enable) */
+ mpc8xx_console_irq_off, /* (rtems_irq_disable) */
+ mpc8xx_console_irq_isOn /* (rtems_irq_is_enabled) */
+ };
+ if (!BSP_install_rtems_irq_handler (&irq_conn_data)) {
+ rtems_panic("console: cannot install IRQ handler");
+ }
+ }
+}
+
+/*
+ * polled scc read function
+ */
+static int
+sccPollRead (int minor)
+{
+ int c = -1;
+ int chan = minor;
+
+ while(1) {
+ if ((sccCurrRxBd[chan]->status & M8xx_BD_EMPTY) != 0) {
+ return -1;
+ }
+
+ if (0 == (sccCurrRxBd[chan]->status & (M8xx_BD_OVERRUN
+ | M8xx_BD_PARITY_ERROR
+ | M8xx_BD_FRAMING_ERROR
+ | M8xx_BD_BREAK
+ | M8xx_BD_IDLE))) {
+ /* character received and no error detected */
+ rtems_cache_invalidate_multiple_data_lines((void *)sccCurrRxBd[chan]->buffer,
+ sccCurrRxBd[chan]->length);
+ c = (unsigned)*((char *)sccCurrRxBd[chan]->buffer);
+ /*
+ * clear status
+ */
+ }
+ sccCurrRxBd[chan]->status =
+ (sccCurrRxBd[chan]->status
+ & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT))
+ | M8xx_BD_EMPTY;
+ /*
+ * advance to next BD
+ */
+ if ((sccCurrRxBd[chan]->status & M8xx_BD_WRAP) != 0) {
+ sccCurrRxBd[chan] = sccFrstRxBd[chan];
+ }
+ else {
+ sccCurrRxBd[chan]++;
+ }
+ if (c >= 0) {
+ return c;
+ }
+ }
+}
+
+
+/*
+ * Device-dependent write routine
+ * Interrupt-driven devices:
+ * Begin transmission of as many characters as possible (minimum is 1).
+ * Polling devices:
+ * Transmit all characters.
+ */
+static ssize_t
+sccInterruptWrite (int minor, const char *buf, size_t len)
+{
+ if (len > 0) {
+ int chan = minor;
+
+ if ((sccPrepTxBd[chan]->status & M8xx_BD_READY) == 0) {
+ sccPrepTxBd[chan]->buffer = (char *)buf;
+ sccPrepTxBd[chan]->length = len;
+ rtems_cache_flush_multiple_data_lines((const void *)buf,len);
+ /*
+ * clear status, set ready bit
+ */
+ sccPrepTxBd[chan]->status =
+ (sccPrepTxBd[chan]->status
+ & M8xx_BD_WRAP)
+ | M8xx_BD_READY | M8xx_BD_INTERRUPT;
+ if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
+ sccPrepTxBd[chan] = sccFrstTxBd[chan];
+ }
+ else {
+ sccPrepTxBd[chan]++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t
+sccPollWrite (int minor, const char *buf, size_t len)
+{
+ static char txBuf[CONS_CHN_CNT][SCC_TXBD_CNT];
+ int chan = minor;
+ int bd_used;
+ size_t retval = len;
+
+ while (len--) {
+ while (sccPrepTxBd[chan]->status & M8xx_BD_READY)
+ continue;
+ bd_used = sccPrepTxBd[chan]-sccFrstTxBd[chan];
+ txBuf[chan][bd_used] = *buf++;
+ rtems_cache_flush_multiple_data_lines((const void *)&txBuf[chan][bd_used],
+ sizeof(txBuf[chan][bd_used]));
+ sccPrepTxBd[chan]->buffer = &(txBuf[chan][bd_used]);
+ sccPrepTxBd[chan]->length = 1;
+ sccPrepTxBd[chan]->status =
+ (sccPrepTxBd[chan]->status
+ & M8xx_BD_WRAP)
+ | M8xx_BD_READY;
+ if ((sccPrepTxBd[chan]->status & M8xx_BD_WRAP) != 0) {
+ sccPrepTxBd[chan] = sccFrstTxBd[chan];
+ }
+ else {
+ sccPrepTxBd[chan]++;
+ }
+ }
+ return retval;
+}
+
+/*
+ * printk basic support
+ */
+int BSP_output_chan = CONS_CHN_NONE; /* channel used for printk operation */
+
+static void console_debug_putc_onlcr(const char c)
+{
+ rtems_interrupt_level irq_level;
+
+ if (BSP_output_chan != CONS_CHN_NONE) {
+ rtems_interrupt_disable(irq_level);
+
+ sccPollWrite (BSP_output_chan,&c,1);
+ rtems_interrupt_enable(irq_level);
+ }
+}
+
+BSP_output_char_function_type BSP_output_char = console_debug_putc_onlcr;
+BSP_polling_getchar_function_type BSP_poll_char = NULL;
+
+
+/*
+***************
+* BOILERPLATE *
+***************
+*/
+
+struct {
+ rtems_device_minor_number minor;
+ int driver_mode;
+} channel_list[] = {
+ {CONS_CHN_SMC1,CONS_SMC1_MODE},
+ {CONS_CHN_SMC2,CONS_SMC2_MODE},
+ {CONS_CHN_SCC1,CONS_SCC1_MODE},
+ {CONS_CHN_SCC2,CONS_SCC2_MODE},
+ {CONS_CHN_SCC3,CONS_SCC3_MODE},
+ {CONS_CHN_SCC4,CONS_SCC4_MODE}
+};
+
+
+/*
+ * Initialize and register the device
+ */
+rtems_device_driver console_initialize(rtems_device_major_number major,
+ rtems_device_minor_number minor,/* ignored */
+ void *arg
+ )
+{
+ rtems_status_code status = RTEMS_SUCCESSFUL;
+ int chan,entry,ttynum;
+ char tty_name[] = "/dev/tty00";
+
+ /*
+ * Set up TERMIOS
+ */
+ rtems_termios_initialize ();
+ /*
+ * init BRG allocataion
+ */
+ sccBRGinit();
+ ttynum = 0;
+ for (entry = 0;
+ (entry < sizeof(channel_list)/sizeof(channel_list[0]))
+ && (status == RTEMS_SUCCESSFUL);
+ entry++) {
+ if (channel_list[entry].driver_mode != CONS_MODE_UNUSED) {
+ /*
+ * Do device-specific initialization
+ */
+ chan = channel_list[entry].minor;
+ m8xx_scc_mode[chan] = channel_list[entry].driver_mode;
+ sccInitialize (chan);
+
+ /*
+ * build device name
+ */
+ tty_name[sizeof(tty_name)-2] = '0'+ttynum;
+ ttynum++;
+ /*
+ * Register the device
+ */
+ status = rtems_io_register_name (tty_name,
+ major,
+ channel_list[entry].minor);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred (status);
+ }
+ }
+ }
+ /*
+ * register /dev/console
+ */
+ status = rtems_io_register_name ("/dev/console",
+ major,
+ CONSOLE_CHN);
+ if (status != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred (status);
+ }
+ /*
+ * enable printk support
+ */
+ BSP_output_chan = PRINTK_CHN;
+
+ 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 status;
+ int chan = minor;
+ rtems_libio_open_close_args_t *args = (rtems_libio_open_close_args_t *)arg;
+ static const rtems_termios_callbacks interruptCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ NULL, /* pollRead */
+ sccInterruptWrite, /* write */
+ sccSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */
+ };
+ static const rtems_termios_callbacks pollCallbacks = {
+ NULL, /* firstOpen */
+ NULL, /* lastClose */
+ sccPollRead, /* pollRead */
+ sccPollWrite, /* write */
+ sccSetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTx */
+ NULL, /* startRemoteTx */
+ 0 /* outputUsesInterrupts */
+ };
+
+ if (m8xx_scc_mode[chan] == TERMIOS_IRQ_DRIVEN) {
+ status = rtems_termios_open (major, minor, arg, &interruptCallbacks);
+ sccttyp[chan] = args->iop->data1;
+ }
+ else {
+ status = rtems_termios_open (major, minor, arg, &pollCallbacks);
+ sccttyp[chan] = args->iop->data1;
+ }
+ return status;
+}
+
+/*
+ * Close the device
+ */
+rtems_device_driver console_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ rtems_status_code rc;
+
+ rc = rtems_termios_close (arg);
+ sccttyp[minor] = NULL;
+
+ return rc;
+
+}
+
+/*
+ * Read from the device
+ */
+rtems_device_driver console_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ 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
+ )
+{
+ return rtems_termios_write (arg);
+}
+
+#if 0
+static int scc_io_set_trm_char(rtems_device_minor_number minor,
+ rtems_libio_ioctl_args_t *ioa)
+{
+ rtems_status_code rc = RTEMS_SUCCESSFUL;
+ con360_io_trm_char_t *trm_char_info = ioa->buffer;
+
+ /*
+ * check, that parameter is non-NULL
+ */
+ if ((rc == RTEMS_SUCCESSFUL) &&
+ (trm_char_info == NULL)) {
+ rc = RTEMS_INVALID_ADDRESS;
+ }
+ /*
+ * transfer max_idl
+ */
+ if (rc == RTEMS_SUCCESSFUL) {
+ if (trm_char_info->max_idl >= 0x10000) {
+ rc = RTEMS_INVALID_NUMBER;
+ }
+ else if (trm_char_info->max_idl > 0) {
+ CHN_PARAM_SET(minor,un.uart.max_idl ,trm_char_info->max_idl);
+ }
+ else if (trm_char_info->max_idl == 0) {
+ CHN_PARAM_SET(minor,un.uart.max_idl ,MAX_IDL_DEFAULT);
+ }
+ }
+ /*
+ * transfer characters
+ */
+ if (rc == RTEMS_SUCCESSFUL) {
+ if (trm_char_info->char_cnt > CON8XX_TRM_CHAR_CNT) {
+ rc = RTEMS_TOO_MANY;
+ }
+ else if (trm_char_info->char_cnt >= 0) {
+ /*
+ * check, whether device is a SCC
+ */
+ if ((rc == RTEMS_SUCCESSFUL) &&
+ !m8xx_console_chan_desc[minor].is_scc) {
+ rc = RTEMS_UNSATISFIED;
+ }
+ else {
+ int idx = 0;
+ for(idx = 0;idx < trm_char_info->char_cnt;idx++) {
+ m8xx_console_chan_desc[minor].parms.sccp->un.uart.character[idx] =
+ trm_char_info->character[idx] & 0x00ff;
+ }
+ if (trm_char_info->char_cnt < CON8XX_TRM_CHAR_CNT) {
+ m8xx_console_chan_desc[minor].parms.sccp
+ ->un.uart.character[trm_char_info->char_cnt] = 0x8000;
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+#endif
+
+/*
+ * Handle ioctl request.
+ */
+rtems_device_driver console_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+ )
+{
+ rtems_libio_ioctl_args_t *ioa=arg;
+
+ switch (ioa->command) {
+#if 0
+ case CON8XX_IO_SET_TRM_CHAR:
+ return scc_io_set_trm_char(minor, ioa);
+#endif
+ default:
+ return rtems_termios_ioctl (arg);
+ break;
+ }
+}
+
diff --git a/bsps/powerpc/virtex/console/consolelite.c b/bsps/powerpc/virtex/console/consolelite.c
new file mode 100644
index 0000000000..4d0b2db17f
--- /dev/null
+++ b/bsps/powerpc/virtex/console/consolelite.c
@@ -0,0 +1,425 @@
+/*
+ * This file contains the console driver for the xilinx uart lite.
+ *
+ * Author: Keith Robertson <kjrobert@alumni.uwaterloo.ca>
+ * COPYRIGHT (c) 2005 by Linn Products Ltd, Scotland.
+ *
+ * Derived from libbsp/no_cpu/no_bsp/console.c and therefore also:
+ *
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ */
+
+#include <assert.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <bsp/irq.h>
+
+#include <bsp.h>
+#include <libchip/serial.h>
+#include <libchip/sersupp.h>
+
+#include RTEMS_XPARAMETERS_H
+
+/* Status Register Masks */
+#define PARITY_ERROR 0x80 /* Parity Error */
+#define FRAME_ERROR 0x40 /* Frame Error */
+#define OVERRUN_ERROR 0x20 /* Overrun Error */
+#define STATUS_REG_ERROR_MASK ( PARITY_ERROR | FRAME_ERROR | OVERRUN_ERROR )
+
+#define INTR_ENABLED 0x10 /* Interrupts are enabled */
+#define TX_FIFO_FULL 0x08 /* Transmit FIFO is full */
+#define TX_FIFO_EMPTY 0x04 /* Transmit FIFO is empty */
+#define RX_FIFO_FULL 0x02 /* Receive FIFO is full */
+#define RX_FIFO_VALID_DATA 0x01 /* Receive FIFO has valid data */
+/* Control Register Masks*/
+#define ENABLE_INTR 0x10 /* Enable interrupts */
+#define RST_RX_FIFO 0x02 /* Reset and clear RX FIFO */
+#define RST_TX_FIFO 0x01 /* Reset and clear TX FIFO */
+
+/* General Defines */
+#define TX_FIFO_SIZE 16
+#define RX_FIFO_SIZE 16
+
+
+
+
+#define RECV_REG 0
+#define TRAN_REG 4
+#define STAT_REG 8
+#define CTRL_REG 12
+
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_control(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+CTRL_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_status(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+STAT_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE uint32_t xlite_uart_read(uint32_t base)
+{
+ uint32_t c = *((volatile uint32_t*)(base+RECV_REG));
+ return c;
+}
+
+
+RTEMS_INLINE_ROUTINE void xlite_uart_write(uint32_t base, char ch)
+{
+ *(volatile uint32_t*)(base+TRAN_REG) = (uint32_t)ch;
+ return;
+}
+
+
+
+static int xlite_write_char(uint32_t base, char ch)
+{
+ uint32_t retrycount= 0, idler, status;
+
+ while( ((status = xlite_uart_status(base)) & TX_FIFO_FULL) != 0 )
+ {
+ ++retrycount;
+
+ /* uart tx is busy */
+ if( retrycount == 0x4000 )
+ {
+ /* retrycount is arbitrary- just make it big enough so the uart is sure to be timed out before it trips */
+ return -1;
+ }
+
+ /* spin for a bit so we can sample the register rather than
+ * continually reading it */
+ for( idler= 0; idler < 0x2000; idler++);
+ }
+
+ xlite_uart_write(base, ch);
+
+ return 1;
+}
+
+static void xlite_init(int minor )
+{
+ /* Nothing to do */
+}
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+static void xlite_interrupt_handler(void *arg)
+{
+ int minor = (int) arg;
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ console_data *cd = &Console_Port_Data[minor];
+ uint32_t base = ct->ulCtrlPort1;
+ uint32_t status = xlite_uart_status(base);
+
+ while ((status & RX_FIFO_VALID_DATA) != 0) {
+ char c = (char) xlite_uart_read(base);
+
+ rtems_termios_enqueue_raw_characters(cd->termios_data, &c, 1);
+
+ status = xlite_uart_status(base);
+ }
+
+ if (cd->bActive) {
+ rtems_termios_dequeue_characters(cd->termios_data, 1);
+ }
+}
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static int xlite_open(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ rtems_status_code sc;
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ /* clear status register */
+ *((volatile uint32_t*)(base+STAT_REG)) = 0;
+
+ /* clear control register; reset fifos */
+ *((volatile uint32_t*)(base+CTRL_REG)) = RST_RX_FIFO | RST_TX_FIFO;
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ *((volatile uint32_t*)(base+CTRL_REG)) = ENABLE_INTR;
+
+ sc = rtems_interrupt_handler_install(
+ ct->ulIntVector,
+ "xlite",
+ RTEMS_INTERRUPT_UNIQUE,
+ xlite_interrupt_handler,
+ (void *) minor
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ return 0;
+}
+
+static int xlite_close(
+ int major,
+ int minor,
+ void *arg
+)
+{
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ rtems_status_code sc;
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ *((volatile uint32_t*)(base+CTRL_REG)) = 0;
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ sc = rtems_interrupt_handler_remove(
+ ct->ulIntVector,
+ xlite_interrupt_handler,
+ (void *) minor
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+ return 0;
+}
+
+
+
+static int xlite_read_polled (int minor )
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+
+ unsigned int status = xlite_uart_status(base);
+
+ if(status & RX_FIFO_VALID_DATA)
+ return (int)xlite_uart_read(base);
+ else
+ return -1;
+}
+
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+
+static ssize_t xlite_write_interrupt_driven(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ console_data *cd = &Console_Port_Data[minor];
+
+ if (len > 0) {
+ const console_tbl *ct = Console_Port_Tbl[minor];
+ uint32_t base = ct->ulCtrlPort1;
+
+ xlite_uart_write(base, buf[0]);
+
+ cd->bActive = true;
+ } else {
+ cd->bActive = false;
+ }
+
+ return 0;
+}
+
+#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static ssize_t xlite_write_buffer_polled(
+ int minor,
+ const char *buf,
+ size_t len
+)
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+ int nwrite = 0;
+
+ /*
+ * poll each byte in the string out of the port.
+ */
+ while (nwrite < len)
+ {
+ if( xlite_write_char(base, *buf++) < 0 ) break;
+ nwrite++;
+ }
+
+ /*
+ * return the number of bytes written.
+ */
+ return nwrite;
+}
+
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+
+static void xlite_write_char_polled(
+ int minor,
+ char c
+)
+{
+ uint32_t base = Console_Port_Tbl[minor]->ulCtrlPort1;
+ xlite_write_char(base, c);
+ return;
+}
+
+static int xlite_set_attributes(int minor, const struct termios *t)
+{
+ return RTEMS_SUCCESSFUL;
+}
+
+
+
+
+
+
+
+static const console_fns xlite_fns_polled =
+{
+ .deviceProbe = libchip_serial_default_probe,
+ .deviceFirstOpen = xlite_open,
+ .deviceLastClose = xlite_close,
+ .deviceRead = xlite_read_polled,
+ .deviceInitialize = xlite_init,
+ .deviceWritePolled = xlite_write_char_polled,
+ .deviceSetAttributes = xlite_set_attributes,
+#if VIRTEX_CONSOLE_USE_INTERRUPTS
+ .deviceWrite = xlite_write_interrupt_driven,
+ .deviceOutputUsesInterrupts = true
+#else /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+ .deviceWrite = xlite_write_buffer_polled,
+ .deviceOutputUsesInterrupts = false
+#endif /* VIRTEX_CONSOLE_USE_INTERRUPTS */
+};
+
+
+
+
+
+
+/*
+** Set ulCtrlPort1 to the base address of each UART Lite instance. Set in vhdl model.
+*/
+
+
+console_tbl Console_Configuration_Ports[] = {
+{
+ "/dev/ttyS0", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ STDIN_BASEADDRESS, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ #ifdef XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
+ .ulIntVector = XPAR_XPS_INTC_0_RS232_UART_INTERRUPT_INTR
+ #else
+ .ulIntVector = 0
+ #endif
+},
+#ifdef XPAR_UARTLITE_1_BASEADDR
+{
+ "/dev/ttyS1", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_1_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+},
+#endif
+#ifdef XPAR_UARTLITE_2_BASEADDR
+{
+ "/dev/ttyS2", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_2_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+},
+#endif
+#ifdef XPAR_UARTLITE_2_BASEADDR
+{
+ "/dev/ttyS3", /* sDeviceName */
+ SERIAL_CUSTOM, /* deviceType */
+ &xlite_fns_polled, /* pDeviceFns */
+ NULL, /* deviceProbe, assume it is there */
+ NULL, /* pDeviceFlow */
+ 16, /* ulMargin */
+ 8, /* ulHysteresis */
+ (void *) NULL, /* NULL */ /* pDeviceParams */
+ XPAR_UARTLITE_3_BASEADDR, /* ulCtrlPort1 */
+ 0, /* ulCtrlPort2 */
+ 0, /* ulDataPort */
+ NULL, /* getRegister */
+ NULL, /* setRegister */
+ NULL, /* unused */ /* getData */
+ NULL, /* unused */ /* setData */
+ 0, /* ulClock */
+ 0 /* ulIntVector -- base for port */
+}
+#endif
+};
+
+unsigned long Console_Configuration_Count =
+ RTEMS_ARRAY_SIZE(Console_Configuration_Ports);
+
+
+#include <rtems/bspIo.h>
+
+static void outputChar(char ch)
+{
+ xlite_write_char_polled( 0, ch );
+}
+
+static int inputChar(void)
+{
+ return xlite_read_polled(0);
+}
+
+BSP_output_char_function_type BSP_output_char = outputChar;
+BSP_polling_getchar_function_type BSP_poll_char = inputChar;
+
+