diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2004-04-12 22:04:28 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2004-04-12 22:04:28 +0000 |
commit | 8430205c224c1bfcb67156e5b97dd44ecd81fd7d (patch) | |
tree | 5ce5170ec6f228407d7ebfab0c1efbf17c495595 /c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c | |
parent | 2004-04-12 David Querbach <querbach@realtime.bc.ca> (diff) | |
download | rtems-8430205c224c1bfcb67156e5b97dd44ecd81fd7d.tar.bz2 |
2004-04-12 David Querbach <querbach@realtime.bc.ca>
* README, configure.ac, mpc5xx/Makefile.am,
mpc5xx/exceptions/raw_exception.c, mpc5xx/exceptions/raw_exception.h,
mpc5xx/timer/timer.c, shared/include/cpuIdent.h: addition of a
significant amount of MPC5xx support as part of the addition of the
SS555 BSP.
* mpc5xx/README, mpc5xx/clock/clock.c,
mpc5xx/console-generic/console-generic.c, mpc5xx/include/console.h,
mpc5xx/include/mpc5xx.h, mpc5xx/irq/irq.c, mpc5xx/irq/irq.h,
mpc5xx/irq/irq_asm.S, mpc5xx/irq/irq_init.c,
mpc5xx/vectors/vectors.S, mpc5xx/vectors/vectors.h,
mpc5xx/vectors/vectors_init.c: New files.
* mpc5xx/exceptions/asm_utils.S: Removed.
Diffstat (limited to 'c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c')
-rw-r--r-- | c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c b/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c new file mode 100644 index 0000000000..89282506a7 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc5xx/console-generic/console-generic.c @@ -0,0 +1,347 @@ +/* + * General Serial I/O functions. + * + * This file contains the functions for performing serial I/O. The actual + * system calls (console_*) should be in the BSP part of the source tree. + * That way different BSPs can use whichever SCI they wish for /dev/console. + * + * On-chip resources used: + * resource minor note + * SCI1 0 + * SCI2 1 + * + * + * MPC5xx 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/libcpu/powerpc/mpc8xx/console_generic/console_generic.c: + * 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-1998. + * 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 + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include <stdlib.h> +#include <unistd.h> +#include <termios.h> +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/bspIo.h> /* for printk */ +#include <mpc5xx.h> +#include <mpc5xx/console.h> +#include <libcpu/irq.h> + + +extern rtems_cpu_table Cpu_table; /* for CPU clock speed */ + +/* + * SCI port descriptor table. + */ +typedef struct +{ + volatile m5xxSCIRegisters_t *regs; /* hardware registers */ + struct rtems_termios_tty *ttyp; /* termios data for this port */ +} sci_desc; + +static sci_desc sci_descs[] = { + { &imb.qsmcm.sci1, 0 }, /* SCI 1 */ + { &imb.qsmcm.sci2, 0 }, /* SCI 2 */ +}; + +/* + * Number of SCI port initialization calls made so far. Used to avoid + * installing the common interrupt handler more than once. + */ +int init_calls = 0; + +/* + * Default configuration. + */ +static struct termios default_termios = { + 0, /* input mode flags */ + 0, /* output mode flags */ + CS8 | CREAD | CLOCAL | B9600, /* control mode flags */ + 0, /* local mode flags */ + 0, /* line discipline */ + { 0 } /* control characters */ +}; + + +/* + * Termios callback functions + */ + +int +m5xx_uart_firstOpen( + int major, + int minor, + void *arg +) +{ + rtems_libio_open_close_args_t *args = arg; + sci_desc* desc = &sci_descs[minor]; + struct rtems_termios_tty *tty = args->iop->data1; + + desc->ttyp = tty; /* connect tty */ + if ( tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN) + desc->regs->sccr1 |= QSMCM_SCI_RIE; /* enable rx interrupt */ + + return RTEMS_SUCCESSFUL; +} + +int +m5xx_uart_lastClose( + int major, + int minor, + void* arg +) +{ + sci_desc* desc = &sci_descs[minor]; + + desc->regs->sccr1 &= ~(QSMCM_SCI_RIE | QSMCM_SCI_TIE); /* disable all */ + desc->ttyp = NULL; /* disconnect tty */ + + return RTEMS_SUCCESSFUL; +} + +int +m5xx_uart_pollRead( + int minor +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + int c = -1; + + if ( regs ) { + while ( (regs->scsr & QSMCM_SCI_RDRF) == 0 ) + ; + c = regs->scdr; + } + + return c; +} + +int +m5xx_uart_write( + int minor, + const char *buf, + int len +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + + regs->scdr = *buf; /* start transmission */ + regs->sccr1 |= QSMCM_SCI_TIE; /* enable interrupt */ + return 0; +} + +int +m5xx_uart_pollWrite( + int minor, + const char *buf, + int len +) +{ + volatile m5xxSCIRegisters_t *regs = sci_descs[minor].regs; + + while ( len-- ) { + while ( (regs->scsr & QSMCM_SCI_TDRE) == 0 ) + ; + regs->scdr = *buf++; + } + return 0; +} + +void +m5xx_uart_reserve_resources( + rtems_configuration_table *configuration +) +{ + rtems_termios_reserve_resources (configuration, NUM_PORTS); +} + +int +m5xx_uart_setAttributes( + int minor, + const struct termios *t +) +{ + rtems_unsigned16 sccr0 = sci_descs[minor].regs->sccr0; + rtems_unsigned16 sccr1 = sci_descs[minor].regs->sccr1; + int baud; + + /* + * Check that port number is valid + */ + if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) + return RTEMS_INVALID_NUMBER; + + /* Baud rate */ + switch (t->c_cflag & CBAUD) { + 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; + } + if (baud > 0) { + sccr0 &= ~QSMCM_SCI_BAUD(-1); + sccr0 |= + QSMCM_SCI_BAUD((Cpu_table.clock_speed + (16 * baud)) / (32 * baud)); + } + + /* Number of data bits -- not available with MPC5xx SCI */ + switch ( t->c_cflag & CSIZE ) { + case CS5: break; + case CS6: break; + case CS7: break; + case CS8: break; + } + + /* Stop bits -- not easily available with MPC5xx SCI */ + if ( t->c_cflag & CSTOPB ) { + /* Two stop bits */ + } else { + /* One stop bit */ + } + + /* Parity */ + if ( t->c_cflag & PARENB ) + sccr1 |= QSMCM_SCI_PE; + else + sccr1 &= ~QSMCM_SCI_PE; + + if ( t->c_cflag & PARODD ) + sccr1 |= QSMCM_SCI_PT; + else + sccr1 &= ~QSMCM_SCI_PT; + + /* Transmitter and receiver enable */ + sccr1 |= QSMCM_SCI_TE; + if ( t->c_cflag & CREAD ) + sccr1 |= QSMCM_SCI_RE; + else + sccr1 &= ~QSMCM_SCI_RE; + + /* Write hardware registers */ + sci_descs[minor].regs->sccr0 = sccr0; + sci_descs[minor].regs->sccr1 = sccr1; + + return RTEMS_SUCCESSFUL; +} + + +/* + * Interrupt handling. + */ +static void +m5xx_sci_interrupt_handler (void) +{ + int minor; + + for ( minor = 0; minor < NUM_PORTS; minor++ ) { + sci_desc *desc = &sci_descs[minor]; + int sccr1 = desc->regs->sccr1; + int scsr = desc->regs->scsr; + + /* + * Character received? + */ + if ((sccr1 & QSMCM_SCI_RIE) && (scsr & QSMCM_SCI_RDRF)) { + char c = desc->regs->scdr; + rtems_termios_enqueue_raw_characters(desc->ttyp, &c, 1); + } + /* + * Transmitter empty? + */ + if ((sccr1 & QSMCM_SCI_TIE) && (scsr & QSMCM_SCI_TDRE)) { + desc->regs->sccr1 &= ~QSMCM_SCI_TIE; + rtems_termios_dequeue_characters (desc->ttyp, 1); + } + } +} + +void m5xx_sci_nop(const rtems_irq_connect_data* ptr) +{ +} + +int m5xx_sci_isOn(const rtems_irq_connect_data* ptr) +{ + return 1; +} + +/* + * Basic initialization. + */ + +void +m5xx_uart_initialize (int minor) +{ + /* + * Check that minor number is valid. + */ + if ( (minor < SCI1_MINOR) || (minor > SCI2_MINOR) ) + return; + + /* + * Configure and enable receiver and transmitter. + */ + m5xx_uart_setAttributes(minor, &default_termios); + + /* + * Connect interrupt if not yet done. + */ + if ( init_calls++ == 0 ) { + rtems_irq_connect_data irq_data; + + irq_data.name = CPU_IRQ_SCI; + irq_data.hdl = m5xx_sci_interrupt_handler; + irq_data.on = m5xx_sci_nop; /* can't enable both channels here */ + irq_data.off = m5xx_sci_nop; /* can't disable both channels here */ + irq_data.isOn = m5xx_sci_isOn; + + if (!CPU_install_rtems_irq_handler (&irq_data)) { + printk("Unable to connect SCI Irq handler\n"); + rtems_fatal_error_occurred(1); + } + + imb.qsmcm.qdsci_il = /* set interrupt level in port */ + QSMCM_ILDSCI(CPU_irq_level_from_symbolic_name(CPU_IRQ_SCI)); + } +} + |