From 2c7e99fd96d3c63328258aa31c2fd083754acd91 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 17 Feb 2009 02:43:47 +0000 Subject: [PATCH] Add M16C serial driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1509 42af7a65-404d-4744-a932-0658087f49c3 --- arch/sh/src/m16c/Make.defs | 4 +- arch/sh/src/m16c/chip.h | 32 +- arch/sh/src/m16c/m16c_dumpstate.c | 18 +- arch/sh/src/m16c/m16c_lowputc.c | 4 +- arch/sh/src/m16c/m16c_serial.c | 1186 +++++++++++++++++++++++++++++ 5 files changed, 1223 insertions(+), 21 deletions(-) create mode 100644 arch/sh/src/m16c/m16c_serial.c diff --git a/arch/sh/src/m16c/Make.defs b/arch/sh/src/m16c/Make.defs index a9a1c21bfb..5c4b2ea8a9 100644 --- a/arch/sh/src/m16c/Make.defs +++ b/arch/sh/src/m16c/Make.defs @@ -43,10 +43,8 @@ CMN_CSRCS = up_allocateheap.c up_assert.c up_blocktask.c \ up_udelay.c up_unblocktask.c up_usestack.c CHIP_ASRCS = m16c_vectors.S -#CHIP_CSRCS = m16c_initialstate.c m16c_copystate.c m16c_lowputc.c m16c_irq.c \ -# m16c_timerisr.c m16c_serial.c m16c_dumpstate.c CHIP_CSRCS = m16c_initialstate.c m16c_copystate.c m16c_lowputc.c m16c_irq.c \ - m16c_timerisr.c m16c_dumpstate.c + m16c_timerisr.c m16c_serial.c m16c_dumpstate.c ifneq ($(CONFIG_DISABLE_SIGNALS),y) CHIP_CSRCS += m16c_schedulesigaction.c m16c_sigdeliver.c diff --git a/arch/sh/src/m16c/chip.h b/arch/sh/src/m16c/chip.h index fccd771a5e..095bb688c5 100644 --- a/arch/sh/src/m16c/chip.h +++ b/arch/sh/src/m16c/chip.h @@ -251,20 +251,28 @@ #ifndef __ASSEMBLY__ -extern uint16 g_snbss; /* Start of near .bss */ -extern uint16 g_enbss; /* End+1 of near .bss */ -extern uint16 g_sndata; /* Start of near .data */ -extern uint16 g_endata; /* End+1 of near .data */ -extern uint32 g_enronly; /* Start of relocated read-only data in FLASH */ +extern uint16 g_snbss; /* Start of near .bss */ +extern uint16 g_enbss; /* End+1 of near .bss */ +extern uint16 g_sndata; /* Start of near .data */ +extern uint16 g_endata; /* End+1 of near .data */ +extern uint32 g_enronly; /* Start of relocated read-only data in FLASH */ #ifdef CONFIG_M16C_HAVEFARRAM -extern uint32 g_sfbss; /* Start of far .bss */ -extern uint32 g_efbss; /* End+1 of far .bss */ -extern uint32 g_sfdata; /* Start of far .data */ -extern uint32 g_efdata; /* End_1 of far .data */ -extern uint32 g_efronly; /* Start of relocated read-only data in FLASH */ + extern uint32 g_sfbss; /* Start of far .bss */ + extern uint32 g_efbss; /* End+1 of far .bss */ + extern uint32 g_sfdata; /* Start of far .data */ + extern uint32 g_efdata; /* End_1 of far .data */ + xtern uint32 g_efronly; /* Start of relocated read-only data in FLASH */ +#endif +extern uint32 g_svarvect; /* Start of variable vectors */ +extern uint32 g_heapbase; /* Start of the heap */ + +/* Address of the saved user stack pointer */ + +#ifndef __ASSEMBLY__ +# if CONFIG_ARCH_INTERRUPTSTACK > 3 + extern uint16 g_userstack; +# endif #endif -extern uint32 g_svarvect; /* Start of variable vectors */ -extern uint32 g_heapbase; /* Start of the heap */ #endif /* __ASSEMBLY__ */ diff --git a/arch/sh/src/m16c/m16c_dumpstate.c b/arch/sh/src/m16c/m16c_dumpstate.c index 6d70d8cee2..11bd990cd1 100755 --- a/arch/sh/src/m16c/m16c_dumpstate.c +++ b/arch/sh/src/m16c/m16c_dumpstate.c @@ -91,6 +91,18 @@ static inline uint16 m16c_getsp(void) return sp; } +/**************************************************************************** + * Name: m16c_getusersp + ****************************************************************************/ + +#if CONFIG_ARCH_INTERRUPTSTACK > 3 +static inline uint16 m16c_getusersp(void) +{ + ubyte *ptr = (ubyte*) current_regs; + return (uint16)ptr[REG_SP] << 8 | ptr[REG_SP+1]; +} +#endif + /**************************************************************************** * Name: m16c_stackdump ****************************************************************************/ @@ -199,11 +211,9 @@ void up_dumpstate(void) m16c_stackdump(sp, istackbase); - /* Extract the user stack pointer which should lie - * at the base of the interrupt stack. - */ + /* Extract the user stack pointer from the register area */ - sp = g_userstack; + sp = m16c_getusersp(); lldbg("sp: %04x\n", sp); } diff --git a/arch/sh/src/m16c/m16c_lowputc.c b/arch/sh/src/m16c/m16c_lowputc.c index 78b2a68af1..861623dc2d 100644 --- a/arch/sh/src/m16c/m16c_lowputc.c +++ b/arch/sh/src/m16c/m16c_lowputc.c @@ -71,8 +71,8 @@ # undef CONFIG_UART2_SERIAL_CONSOLE #elif defined(CONFIG_UART2_SERIAL_CONSOLE) && !defined(CONFIG_UART2_DISABLE) # define HAVE_CONSOLE 1 +# undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE -# undef CONFIG_UART2_SERIAL_CONSOLE #else # if defined(CONFIG_UART0_SERIAL_CONSOLE) || defined(CONFIG_UART1_SERIAL_CONSOLE)|| defined(CONFIG_UART2_SERIAL_CONSOLE) # error "Serial console selected, but corresponding UART not enabled" @@ -183,7 +183,7 @@ #ifdef HAVE_CONSOLE static inline int up_txready(void) { - /* Check the TI bit in the CI register. 1=Transmit buffer emptyy */ + /* Check the TI bit in the CI register. 1=Transmit buffer empty */ return ((getreg8(M16C_UART_BASE + M16C_UART_C1) & UART_C1_TI) != 0); } diff --git a/arch/sh/src/m16c/m16c_serial.c b/arch/sh/src/m16c/m16c_serial.c new file mode 100644 index 0000000000..12b6148643 --- /dev/null +++ b/arch/sh/src/m16c/m16c_serial.c @@ -0,0 +1,1186 @@ +/**************************************************************************** + * arch/sh/src/m16c/m16c_serial.c + * + * Copyright (C) 2009 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chip.h" +#include "up_arch.h" +#include "up_internal.h" +#include "os_internal.h" +#include "m16c_uart.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +/* Configuration **********************************************************/ + +#ifndef M16C_XIN_PRESCALER +# define M16C_XIN_PRESCALER 1 +#endif + +/* Make sure interrupt priorities are defined. If not, use a default of 5 */ + +#ifndef M16C_S2T_PRIO +# define M16C_S2T_PRIO 5 /* UART2 transmit interrupt priority */ +#endif +#ifndef M16C_S2R_PRIO +# define M16C_S2R_PRIO 5 /* UART2 receive interrupt priority */ +#endif +#ifndef M16C_S0T_PRIO +# define M16C_S0T_PRIO 5 /* UART0 transmit interrupt priority */ +#endif +#ifndef M16C_S0R_PRIO +# define M16C_S0R_PRIO 5 /* UART0 receive interrupt priority */ +#endif +#ifndef M16C_S1T_PRIO +# define M16C_S1T_PRIO 5 /* UART1 transmit interrupt priority */ +#endif +#ifndef M16C_S1R_PRIO +# define M16C_S1R_PRIO 5 /* UART1 receive interrupt priority */ +#endif + +/* Some sanity checks *******************************************************/ + +/* Are there any UARTs? */ + +#if defined(CONFIG_UART0_DISABLE) && defined(CONFIG_UART1_DISABLE) && defined(CONFIG_UART2_DISABLE) +# ifdef CONFIG_USE_SERIALDRIVER +# error "Serial driver selected, but UARTs not enabled" +# undef CONFIG_USE_SERIALDRIVER +# endif +#endif + +/* Is there a serial console? */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) && !defined(CONFIG_UART0_DISABLE) +# define HAVE_CONSOLE 1 +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && !defined(CONFIG_UART1_DISABLE) +# define HAVE_CONSOLE 1 +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) && !defined(CONFIG_UART2_DISABLE) +# define HAVE_CONSOLE 1 +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +#else +# if defined(CONFIG_UART0_SERIAL_CONSOLE) || defined(CONFIG_UART1_SERIAL_CONSOLE)|| defined(CONFIG_UART2_SERIAL_CONSOLE) +# error "Serial console selected, but corresponding UART not enabled" +# endif +# undef HAVE_CONSOLE +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +#endif + +#ifdef CONFIG_USE_SERIALDRIVER + +/* Which UART with be tty0/console and which tty1 and tty2? */ + +/* CONFIG_UART0_SERIAL_CONSOLE (implies CONFIG_UART0_DISABLE also un-defined) */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart0port /* UART0 is console */ +# define TTYS0_DEV g_uart0port /* UART0 is tty0 */ +# ifndef CONFIG_UART1_DISABLE +# define TTYS1_DEV g_uart1port /* UART1 is tty1 */ +# ifndef CONFIG_UART2_DISABLE +# define TTYS2_DEV g_uart2port /* UART2 is tty2 */ +# endif +# else +# ifndef CONFIG_UART2_DISABLE +# define TTYS2_DEV g_uart2port /* UART2 is tty1 */ +# else +# undef TTYS1_DEV /* No tty1 */ +# endif +# undef TTYS2_DEV /* No tty2 */ +# endif + +/* CONFIG_UART1_SERIAL_CONSOLE (implies CONFIG_UART1_DISABLE also un-defined) */ + +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1 is console */ +# define TTYS0_DEV g_uart1port /* UART1 is tty0 */ +# ifndef CONFIG_UART0_DISABLE +# define TTYS1_DEV g_uart0port /* UART0 is tty1 */ +# ifndef CONFIG_UART2_DISABLE +# define TTYS2_DEV g_uart2port /* UART2 is tty2 */ +# endif +# else +# ifndef CONFIG_UART2_DISABLE +# define TTYS2_DEV g_uart2port /* UART2 is tty1 */ +# else +# undef TTYS1_DEV /* No tty1 */ +# endif +# undef TTYS2_DEV /* No tty2 */ +# endif + +/* CONFIG_UART2_SERIAL_CONSOLE (implies CONFIG_UART2_DISABLE also un-defined) */ + +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart2port /* UART2 is console */ +# define TTYS0_DEV g_uart2port /* UART2 is tty0 */ +# ifndef CONFIG_UART0_DISABLE +# define TTYS1_DEV g_uart0port /* UART0 is tty1 */ +# ifndef CONFIG_UART1_DISABLE +# define TTYS2_DEV g_uart1port /* UART1 is tty2 */ +# endif +# else +# ifndef CONFIG_UART1_DISABLE +# define TTYS1_DEV g_uart1port /* UART1 is tty1 */ +# else +# undef TTYS1_DEV /* No tty1 */ +# endif +# undef TTYS2_DEV /* No tty2 */ +# endif + +/* No console, at least one of CONFIG_UART0/1/2_DISABLE defined */ + +#elif !defined(CONFIG_UART0_DISABLE) +# undef CONSOLE_DEV /* No console */ +# define TTYS0_DEV g_uart0port /* UART0 is tty0 */ +# ifndef CONFIG_UART1_DISABLE +# define TTYS1_DEV g_uart1port /* UART1 is tty1 */ +# ifndef CONFIG_UART2_DISABLE +# define TTYS2_DEV g_uart2port /* UART2 is tty2 */ +# endif +# else +# ifndef CONFIG_UART2_DISABLE +# define TTYS1_DEV g_uart1port /* UART2 is tty1 */ +# else +# undef TTYS1_DEV /* No tty1 */ +# endif +# undef TTYS2_DEV /* No tty2 */ +# endif + +elif !defined(CONFIG_UART1_DISABLE) +# undef CONSOLE_DEV /* No console */ +# undef TTYS2_DEV /* No tty2 */ +# define TTYS0_DEV g_uart1port /* UART1 is tty0 */ +# ifndef CONFIG_UART2_DISABLE +# define TTYS1_DEV g_uart2port /* UART2 is tty1 */ +# else +# undef TTYS1_DEV /* No tty1 */ +# endif + +/* Otherwise, there is no console and only CONFIG_UART2_DISABLE is un-defined */ + +#else +# undef CONSOLE_DEV /* No console */ +# define TTYS0_DEV g_uart2port /* UART2 is tty0 */ +# undef TTYS1_DEV /* No tty1 */ +# undef TTYS1_DEV /* No tty2 */ +#endif + +/* Definitions for the enable field of the device structure */ + +#define M16C_RXENABLED 0x01 +#define M16C_TXENABLED 0x02 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + uint32 baud; /* Configured baud */ + uint16 uartbase; /* Base address of UART registers */ + ubyte uartno; /* UART number */ + volatile ubyte ucon; /* Saved SCR value */ + volatile ubyte ssr; /* Saved SR value (only used during interrupt processing) */ + ubyte rcvirq; /* UART receive data available IRQ */ + ubyte xmtirq; /* UART transmit complete IRQ */ + ubyte enables; /* Bit 0: 1=RX enabled, Bit 1: 1=TX enabled */ + ubyte parity; /* 0=none, 1=odd, 2=even */ + ubyte bits; /* Number of bits (7 or 8) */ + boolean stopbits2; /* TRUE: Configure with 2 stop bits instead of 1 */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int up_setup(struct uart_dev_s *dev); +static void up_shutdown(struct uart_dev_s *dev); +static int up_attach(struct uart_dev_s *dev); +static void up_detach(struct uart_dev_s *dev); +static int up_rcvinterrupt(int irq, void *context); +static int up_receive(struct uart_dev_s *dev, unsigned int *status); +static void m16c_rxint(struct up_dev_s *dev, boolean enable); +static void up_rxint(struct uart_dev_s *dev, boolean enable); +static boolean up_rxavailable(struct uart_dev_s *dev); +static int up_xmtinterrupt(int irq, void *context); +static void up_send(struct uart_dev_s *dev, int ch); +static void m16c_txint(struct up_dev_s *dev, boolean enable); +static void up_txint(struct uart_dev_s *dev, boolean enable); +static boolean up_txready(struct uart_dev_s *dev); + +/**************************************************************************** + * Private Variables + ****************************************************************************/ + +struct uart_ops_s g_uart_ops = +{ + .setup = up_setup, + .shutdown = up_shutdown, + .attach = up_attach, + .detach = up_detach, + .receive = up_receive, + .rxint = up_rxint, + .rxavailable = up_rxavailable, + .send = up_send, + .txint = up_txint, + .txready = up_txready, + .txempty = up_txready, +}; + +/* I/O buffers */ + +#ifndef CONFIG_UART0_DISABLE +static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; +static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; +#endif +#ifndef CONFIG_UART1_DISABLE +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; +#endif +#ifndef CONFIG_UART2_DISABLE +static char g_uart2rxbuffer[CONFIG_UART2_RXBUFSIZE]; +static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE]; +#endif + +/* This describes the state of the M16C UART0 port. */ + +#ifndef CONFIG_UART0_DISABLE +static struct up_dev_s g_uart0priv = +{ + .baud = CONFIG_UART0_BAUD, + .uartbase = M16C_UART0_BASE, + .uartno = 0, + .rcvirq = M16C_UART0RCV_IRQ, + .xmtirq = M16C_UART0XMT_IRQ, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, +}; + +static uart_dev_t g_uart0port = +{ + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +/* This describes the state of the M16C UART1 port. */ + +#ifndef CONFIG_UART1_DISABLE +static struct up_dev_s g_uart1priv = +{ + .baud = CONFIG_UART1_BAUD, + .uartbase = M16C_UART1_BASE, + .uartno = 1, + .rcvirq = M16C_UART1RCV_IRQ, + .xmtirq = M16C_UART1XMT_IRQ, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, +}; + +static uart_dev_t g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +/* This describes the state of the M16C UART2 port. */ + +#ifndef CONFIG_UART2_DISABLE +static struct up_dev_s g_uart2priv = +{ + .baud = CONFIG_UART2_BAUD, + .uartbase = M16C_UART2_BASE, + .uartno = 2, + .rcvirq = M16C_UART2RCV_IRQ, + .xmtirq = M16C_UART2XMT_IRQ, + .parity = CONFIG_UART2_PARITY, + .bits = CONFIG_UART2_BITS, + .stopbits2 = CONFIG_UART2_2STOP, +}; + +static uart_dev_t g_uart2port = +{ + .recv = + { + .size = CONFIG_UART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_serialin + ****************************************************************************/ + +static inline ubyte up_serialin(struct up_dev_s *priv, int offset) +{ + return getreg8(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_serialin16 + ****************************************************************************/ + +static inline uint16 up_serialin16(struct up_dev_s *priv, int offset) +{ + return getreg16(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout + ****************************************************************************/ + +static inline void up_serialout(struct up_dev_s *priv, int offset, ubyte value) +{ + putreg8(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_serialout16 + ****************************************************************************/ + +static inline void up_serialout16(struct up_dev_s *priv, int offset, uint16 value) +{ + putreg16(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: up_disableuartint + ****************************************************************************/ + +static inline void up_disableuartint(struct up_dev_s *priv, ubyte *penables) +{ + ubyte enables = priv->enables; + m16c_txint(priv, FALSE); + m16c_rxint(priv, FALSE); + + if (enables) + { + *penables = enables; + } +} + +/**************************************************************************** + * Name: up_restoreuartint + ****************************************************************************/ + +static inline void up_restoreuartint(struct up_dev_s *priv, ubyte enables) +{ + m16c_rxint(priv, (enables & M16C_RXENABLED) != 0); + m16c_txint(priv, (enables & M16C_TXENABLED) != 0); +} + +/**************************************************************************** + * Name: up_waittxready + ****************************************************************************/ + +#ifdef HAVE_CONSOLE +static inline void up_waittxready(struct up_dev_s *priv) +{ + int tmp; + + /* Limit how long we will wait for the TDR empty condition */ + + for (tmp = 1000 ; tmp > 0 ; tmp--) + { + /* Check the TI bit in the CI register. 1=Transmit buffer empty */ + + if ((up_serialin(priv, M16C_UART_C1) & UART_C1_TI) != 0); + { + /* The transmit buffer is empty... return */ + break; + } + } +} +#endif + +/**************************************************************************** + * Name: ub_setbrg + * + * Description: + * Calculate the correct value for the BRG given the configured frequency + * and the desired BAUD settings. + * + ****************************************************************************/ + +static inline void ub_setbrg(struct up_dev_s *priv, unsigned int baud) +{ + uint16 brg; + + /* The Bit Rate Generator (BRG) value can be calculated by: + * + * BRG = source-frequency / prescaler / 16 / baud rate - 1 + * + * Example: + * source-frequency = 20,000,000 (20MHz) + * prescaler = 1 + * baud rate = 19200 + * BRG = 20,000,000/1/16/19200 - 1 = 64 + */ + + brg = (M16C_XIN_FREQ / (16L * M16C_XIN_PRESCALER * (uint32)baud)) - 1; + up_serialout(priv, M16C_UART_BRG, brg); +} + +/**************************************************************************** + * Name: up_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial port is + * opened. + * + ****************************************************************************/ + +static int up_setup(struct uart_dev_s *dev) +{ +#ifndef CONFIG_SUPPRESS_UART_CONFIG + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + ubyte regval; + + /* Set the baud rate generator */ + + ub_setbrg(priv, priv->baud); + + /* Disable CTS/RTS */ + + up_serialout(priv, M16C_UART_C0, UART_C0_CRD); + + /* Disable RX/TX interrupts */ + + m16c_rxint(priv, FALSE); + m16c_txint(priv, FALSE); + +/* Set interrupt cause=TX complete and continuous receive mode */ + +#ifndef CONFIG_UART0_DISABLE + if (priv->uartno == 0) + { + regval = getreg8(M16C_UCON); + regval |= (UART_CON_U0IRS|UART_CON_U0RRM); + putreg8(regval, M16C_UCON); + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (priv->uartno == 1) + { + regval = getreg8(M16C_UCON); + regval |= (UART_CON_U1IRS|UART_CON_U1RRM); + putreg8(regval, M16C_UCON); + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (priv->uartno == 2) + { + regval = getreg8(M16C_U2C1); + regval |= ((UART_C1_U2IRS|UART_C1_U2RRM); + putreg8(regval, M16C_U2C1); + } + else +#endif + { + dbg("Invalid UART #\n"); + } + + /* Set UART transmit/receive control register 1 to enable transmit and receive */ + + up_serialout(priv, M16C_UART_C1, UART_C1_TE|UART_C1_RE); + + /* Set UART transmit/receive mode register data bits, stop bits, parity */ + + regval = 0; + + if (priv->bits == 7) + { + regval |= UART_MR_SMD7BITS; + } + else if (priv->bits == 8) + { + regval |= UART_MR_SMD8BITS; + } + else if (priv->bits == 9) + { + regval |= UART_MR_SMD9BITS; + } + else + { + dbg("Invalid bits=%d\n", priv->bits); + } + + if (priv->parity != 0) + { + regval |= UART_MR_PRYE; + if (priv->parity == 2) + { + regval |= UART_MR_PRY; + } + } + + if (priv->stopbits2) + { + regval |= UART_MR_STPS; + } + + up_serialout(priv, M16C_UART_MR, regval); + + /* Set port direction registers for Rx/TX pins */ + +#ifndef CONFIG_UART0_DISABLE + if (priv->uartno == 0) + { + regval = getreg8(M16C_PD6); + regval &= ~(1 << 2); /* PD6-2:RxD1 */ + regval |= (1 << 3); /* PD6-3:TxD1 */ + putreg8(regval, M16C_PD6); + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (priv->uartno == 1) + { + regval = getreg8(M16C_PD6); + regval &= ~(1 << 6); /* PD6-6:RxD1 */ + regval |= (1 << 7); /* PD6-7:TxD1 */ + putreg8(regval, M16C_PD6); + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (priv->uartno == 2) + { + regval = getreg8(M16C_PD7); + regval &= ~(1 << 1); /* PD7-1:RxD1 */ + regval &= (1 << 0); /* PD7-0:TxD1 */ + putreg8(regval, M16C_PD7); + } + else +#endif + { + dbg("Invalid UART #\n"); + } + + /* Read any data left in the RX fifo */ + + regval = (ubyte)up_serialin16(priv, M16C_UART_RB); +#endif + return OK; +} + +/**************************************************************************** + * Name: up_shutdown + * + * Description: + * Disable the UART. This method is called when the serial port is closed + * + ****************************************************************************/ + +static void up_shutdown(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + up_disableuartint(priv, NULL); +} + +/**************************************************************************** + * Name: up_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method is + * called when the serial port is opened. Normally, this is just after the + * the setup() method is called, however, the serial console may operate in + * a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless the + * hardware supports multiple levels of interrupt enabling). The RX and TX + * interrupts are not enabled until the txint() and rxint() methods are called. + * + ****************************************************************************/ + +static int up_attach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + int ret; + + /* Attach the UART receive data available IRQ */ + + ret = irq_attach(priv->rcvirq, up_rcvinterrupt); + if (ret == OK) + { + /* Attach the UART transmit complete IRQ */ + + ret = irq_attach(priv->xmtirq, up_xmtinterrupt); + if (ret != OK) + { + /* Detach the ERI interrupt on failure */ + + (void)irq_detach(priv->rcvirq); + } + } + + return ret; +} + +/**************************************************************************** + * Name: up_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port is + * closed normally just before the shutdown method is called. The exception is + * the serial console which is never shutdown. + * + ****************************************************************************/ + +static void up_detach(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + + /* Disable all UART interrupts */ + + up_disableuartint(priv, NULL); + + /* Detach the UART interrupts */ + + (void)irq_detach(priv->rcvirq); + (void)irq_detach(priv->xmtirq); +} + +/**************************************************************************** + * Name: up_recvinterrupt + * + * Description: + * This is the UART receive interrupt handler. It will be invoked when an + * interrupt received on the 'irq' It should call uart_receivechar to + * perform the appropriate data transfer. The interrupt handling logic + * must be able to map the 'irq' number into the approprite up_dev_s + * structure in order to call these functions. + * + ****************************************************************************/ + +static int up_rcvinterrupt(int irq, void *context) +{ + struct uart_dev_s *dev = NULL; + +#ifndef CONFIG_UART0_DISABLE + if (irq == g_uart0priv.rcvirq) + { + dev = &g_uart0port; + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (irq == g_uart1priv.rcvirq) + { + dev = &g_uart1port; + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (irq = g_uart2priv.rcvirq) + { + dev = &g_uart2port; + } + else +#endif + { + PANIC(OSERR_INTERNAL); + } + + /* Handle incoming, receive bytes (RDRF: Receive Data Register Full) */ + + uart_recvchars(dev); + return OK; +} + +/**************************************************************************** + * Name: up_receive + * + * Description: + * Called (usually) from the interrupt level to receive one character from + * the UART. Error bits associated with the receipt are provided in the + * return 'status'. + * + ****************************************************************************/ + +static int up_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + uint16 rb; + + /* Read the character from the readbuffer */ + + rb = up_serialin16(priv, M16C_UART_RB); + + /* Return the received byte with the receive status */ + + *status = rb; + + /* Return the received character (up to 9 bits) */ + + return (int)(rb & 0x01ff); +} + +/**************************************************************************** + * Name: m16c_rxint, up_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void m16c_rxint(struct up_dev_s *dev, boolean enable) +{ + irqstate_t flags; + uint16 regaddr; + ubyte regvalue; + + /* Disable interrupts to prevent asynchronous accesses */ + + flags = irqsave(); + + /* Pick the SxTIC register and enable interrupt priority */ + +#ifndef CONFIG_UART0_DISABLE + if (dev->uartno == 0) + { + regaddr = M16C_S0RIC; + regvalue = M16C_S0R_PRIO; + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (dev->uartno == 1) + { + regaddr = M16C_S1RIC; + regvalue = M16C_S1R_PRIO; + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (dev->uartno == 2) + { + regaddr = M16C_S2RIC; + regvalue = M16C_S2R_PRIO; + } + else +#endif + { + dbg("Invalid UART #\n"); + return; + } + + /* Are we enabling or disabling? */ + + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + putreg8(regvalue, regaddr); +#endif + dev->enables |= M16C_RXENABLED; + } + else + { + putreg8(0, regaddr); + dev->enables = ~M16C_RXENABLED; + } + + asm ("\tnop\n\tnop\n\tnop"); /* Three NOPs -- probably not necessary here */ + irqrestore(flags); +} + +static void up_rxint(struct uart_dev_s *dev, boolean enable) +{ + m16c_rxint((struct up_dev_s*)dev->priv, enable); +} + +/**************************************************************************** + * Name: up_rxavailable + * + * Description: + * Return TRUE if the RDR is not empty + * + ****************************************************************************/ + +static boolean up_rxavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + + /* Return true if the there is data available in the read buffer */ + + return ((up_serialin(priv, M16C_UART_C1) & UART_C1_RI) != 0); +} + +/**************************************************************************** + * Name: up_xmtvinterrupt + * + * Description: + * This is the UART receive interrupt handler. It will be invoked + * when an interrupt received on the 'irq' It should call + * uart_transmitchars or uart_receivechar to perform the + * appropriate data transfers. The interrupt handling logic\ + * must be able to map the 'irq' number into the approprite + * up_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int up_xmtinterrupt(int irq, void *context) +{ + struct uart_dev_s *dev = NULL; + +#ifndef CONFIG_UART0_DISABLE + if (irq == g_uart0priv.xmtirq) + { + dev = &g_uart0port; + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (irq == g_uart1priv.xmtirq) + { + dev = &g_uart1port; + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (irq == g_uart2priv.xmtirq) + { + dev = &g_uart1port; + } + else +#endif + { + PANIC(OSERR_INTERNAL); + } + + /* Handle outgoing, transmit bytes */ + + uart_xmitchars(dev); + return OK; +} + +/**************************************************************************** + * Name: up_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void up_send(struct uart_dev_s *dev, int ch) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + + /* Write the data to the transmit buffer */ + + up_serialout16(priv, M16C_UART_TB, (uint16)ch); +} + +/**************************************************************************** + * Name: m16c_txint, up_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void m16c_txint(struct up_dev_s *dev, boolean enable) +{ + irqstate_t flags; + uint16 regaddr; + ubyte regvalue; + + /* Disable interrupts to prevent asynchronous accesses */ + + flags = irqsave(); + + /* Pick the SxTIC register and enable interrupt priority */ + +#ifndef CONFIG_UART0_DISABLE + if (dev->uartno == 0) + { + regaddr = M16C_S0TIC; + regvalue = M16C_S0T_PRIO; + } + else +#endif +#ifndef CONFIG_UART1_DISABLE + if (dev->uartno == 1) + { + regaddr = M16C_S1TIC; + regvalue = M16C_S1T_PRIO; + } + else +#endif +#ifndef CONFIG_UART2_DISABLE + if (dev->uartno == 2) + { + regaddr = M16C_S2TIC; + regvalue = M16C_S2T_PRIO; + } + else +#endif + { + dbg("Invalid UART #\n"); + return; + } + + /* Are we enabling or disabling? */ + + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + putreg8(regvalue, regaddr); +#endif + dev->enables |= M16C_TXENABLED; + } + else + { + putreg8(0, regaddr); + dev->enables = ~M16C_TXENABLED; + } + + asm ("\tnop\n\tnop\n\tnop"); /* Three NOPs -- probably not necessary here */ + irqrestore(flags); +} + +static void up_txint(struct uart_dev_s *dev, boolean enable) +{ + m16c_txint((struct up_dev_s*)dev->priv, enable); +} + +/**************************************************************************** + * Name: up_txready + * + * Description: + * Return TRUE if the TDR is empty + * + ****************************************************************************/ + +static boolean up_txready(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s*)dev->priv; + return ((up_serialin(priv, M16C_UART_C1) & UART_C1_TI) != 0); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Performs the low level UART initialization early in + * debug so that the serial console will be available + * during bootup. This must be called before up_serialinit. + * + ****************************************************************************/ + +void up_earlyserialinit(void) +{ + /* NOTE: All GPIO configuration for the UARTs was performed in + * up_lowsetup + */ + + /* Disable all UARTs */ + +#ifdef TTYS0_DEV + up_disableuartint(TTYS0_DEV.priv, NULL); +#ifdef TTYS1_DEV + up_disableuartint(TTYS1_DEV.priv, NULL); +#ifdef TTYS2_DEV + up_disableuartint(TTYS2_DEV.priv, NULL); +#endif +#endif +#endif + + /* Configuration whichever one is the console */ + +#ifdef HAVE_CONSOLE + CONSOLE_DEV.isconsole = TRUE; + up_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: up_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that up_earlyserialinit was called previously. + * + ****************************************************************************/ + +void up_serialinit(void) +{ + /* Register the console */ + +#ifdef HAVE_CONSOLE + (void)uart_register("/dev/console", &CONSOLE_DEV); +#endif + + /* Register all UARTs */ + +#ifdef TTYS0_DEV + (void)uart_register("/dev/ttyS0", &TTYS0_DEV); +#ifdef TTYS1_DEV + (void)uart_register("/dev/ttyS1", &TTYS1_DEV); +#ifdef TTYS2_DEV + (void)uart_register("/dev/ttyS2", &TTYS2_DEV); +#endif +#endif +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_CONSOLE + struct up_dev_s *priv = (struct up_dev_s*)CONSOLE_DEV.priv; + ubyte ucon; + + up_disableuartint(priv, &ucon); + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_waittxready(priv); + up_serialout16(priv, M16C_UART_TB, (uint16)'\r'); + } + + up_waittxready(priv); + up_serialout16(priv, M16C_UART_TB, (uint16)ch); + + up_waittxready(priv); + up_restoreuartint(priv, ucon); +#endif + return ch; +} + +#else /* CONFIG_USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef HAVE_CONSOLE + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + up_lowputc('\r'); + } + + up_lowputc(ch); +#endif + return ch; +} + +#endif /* CONFIG_USE_SERIALDRIVER */