risc-v/mpfs: serial: add termios support and init device clocks

This commit is contained in:
Janne Rosberg 2021-06-22 14:42:33 +03:00 committed by Xiang Xiao
parent aa057e25f2
commit 7db3456824
3 changed files with 247 additions and 54 deletions

View File

@ -57,14 +57,6 @@
#define MPFS_UART_RTO_OFFSET 0x004C /* UART Receiver time-out register */
#define MPFS_UART_ADR_OFFSET 0x0050 /* UART Address register */
/* Register virtual addresses ***********************************************/
#define MPFS250_UART0_VADDR MPFS_UART0_BASE
#define MPFS250_UART1_VADDR MPFS_UART1_BASE
#define MPFS250_UART2_VADDR MPFS_UART2_BASE
#define MPFS250_UART3_VADDR MPFS_UART3_BASE
#define MPFS250_UART4_VADDR MPFS_UART4_BASE
/* Register bit field definitions *******************************************/
/* UART Receive Buffer Register */
@ -89,7 +81,6 @@
#define UART_IER_ETBEI (1 << 1) /* Bit 1: Enable Transmit Holding Register Empty Interrupt */
#define UART_IER_ELSI (1 << 2) /* Bit 2: Enable Receiver Line Status Interrupt */
#define UART_IER_EDSSI (1 << 3) /* Bit 3: Enable Modem Status Interrupt */
#define UART_IER_PTIME (1 << 7) /* Bit 7: Programmable THRE Interrupt Mode Enable */
#define UART_IER_ALLIE 0x0000008f
/* UART Interrupt Identity Register */

View File

@ -48,6 +48,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART0_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART0_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART0_2STOP
# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_MMUART0
# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_MMUART0
# define HAVE_UART
#elif defined(CONFIG_UART1_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART1_BASE
@ -55,6 +57,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART1_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART1_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART1_2STOP
# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_MMUART1
# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_MMUART1
# define HAVE_UART
#elif defined(CONFIG_UART2_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART2_BASE
@ -62,6 +66,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART2_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART2_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART2_2STOP
# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_MMUART2
# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_MMUART2
# define HAVE_UART
# elif defined(CONFIG_UART3_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART3_BASE
@ -69,6 +75,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART3_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART3_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART3_2STOP
# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_MMUART3
# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_MMUART3
# define HAVE_UART
# elif defined(CONFIG_UART4_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART4_BASE
@ -76,6 +84,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART4BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART4_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART4_2STOP
# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_MMUART4
# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_MMUART4
# define HAVE_UART
# elif defined(HAVE_UART)
# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting"
@ -178,14 +188,24 @@ void mpfs_lowsetup(void)
/* Enable and configure the selected console device */
/* REVISIT: bringup UART from reset and set clocking.
* Currently done by HSS bootloader
*/
#if defined(HAVE_SERIAL_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG)
uint32_t lcr = 0;
lcr = 0;
/* reset on */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
0, MPFS_CONSOLE_RESETBIT);
/* reset off */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
0, MPFS_CONSOLE_CLOCKBIT);
/* clock on */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
MPFS_CONSOLE_RESETBIT, 0);
switch (MPFS_CONSOLE_BITS)
{
case 5:

View File

@ -35,17 +35,21 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h>
#include <arch/board/board.h>
#ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>
#endif
#include "riscv_arch.h"
#include "riscv_internal.h"
#include <arch/board/board.h>
#include "chip.h"
#include "mpfs.h"
#include "mpfs_config.h"
#include "mpfs_clockconfig.h"
#include "riscv_arch.h"
#include "riscv_internal.h"
/****************************************************************************
* Pre-processor Definitions
@ -341,7 +345,7 @@ static uart_dev_t g_uart4port =
},
.xmit =
{
.size = CONFIG_UART3_TXBUFSIZE,
.size = CONFIG_UART4_TXBUFSIZE,
.buffer = g_uart4txbuffer,
},
.ops = &g_uart_ops,
@ -417,6 +421,64 @@ static inline void up_enablebreaks(struct up_dev_s *priv, bool enable)
up_serialout(priv, MPFS_UART_LCR_OFFSET, lcr);
}
static void up_enable_uart(struct up_dev_s *priv, bool enable)
{
uint32_t clock_bit = 0;
uint32_t reset_bit = 0;
switch (priv->uartbase)
{
case MPFS_UART0_BASE:
clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART0;
reset_bit = SYSREG_SOFT_RESET_CR_MMUART0;
break;
case MPFS_UART1_BASE:
clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART1;
reset_bit = SYSREG_SOFT_RESET_CR_MMUART1;
break;
case MPFS_UART2_BASE:
clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART2;
reset_bit = SYSREG_SOFT_RESET_CR_MMUART2;
break;
case MPFS_UART3_BASE:
clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART3;
reset_bit = SYSREG_SOFT_RESET_CR_MMUART3;
break;
case MPFS_UART4_BASE:
clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART4;
reset_bit = SYSREG_SOFT_RESET_CR_MMUART4;
break;
default:
return;
}
/* reset on */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
0, reset_bit);
if (enable)
{
/* reset off */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
0, reset_bit);
/* clock on */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET,
clock_bit, 0);
}
else
{
/* clock off */
modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET,
clock_bit, 0);
}
}
/****************************************************************************
* Name: up_config_baud_divisors
*
@ -465,46 +527,21 @@ static void up_config_baud_divisors(struct up_dev_s *priv, uint32_t baudrate)
}
/****************************************************************************
* Name: up_setup
* Name: up_set_format
*
* Description:
* Configure the UART baud, bits, parity, etc. This method is called the
* first time that the serial port is opened.
* Set the serial line format and speed.
*
****************************************************************************/
static int up_setup(struct uart_dev_s *dev)
{
#ifndef CONFIG_SUPPRESS_UART_CONFIG
static void up_set_format(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
uint32_t lcr;
/* Clear fifos */
up_serialout(priv, MPFS_UART_FCR_OFFSET,
(UART_FCR_RFIFOR | UART_FCR_XFIFOR));
/* set filter to minimum value */
up_serialout(priv, MPFS_UART_GFR_OFFSET, 0);
/* set default TX time guard */
up_serialout(priv, MPFS_UART_TTG_OFFSET, 0);
/* Set trigger */
up_serialout(priv, MPFS_UART_FCR_OFFSET,
(UART_FCR_FIFOE | UART_FCR_RT_HALF));
/* Set up the IER */
priv->ier = up_serialin(priv, MPFS_UART_IER_OFFSET);
uint32_t lcr = 0;
/* Set up the LCR */
lcr = 0;
switch (priv->bits)
{
case 5:
@ -550,6 +587,49 @@ static int up_setup(struct uart_dev_s *dev)
/* Clear DLAB */
up_serialout(priv, MPFS_UART_LCR_OFFSET, lcr);
}
#endif
/****************************************************************************
* Name: up_setup
*
* Description:
* Configure the UART baud, bits, parity, 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;
/* enable clock */
up_enable_uart(priv, true);
/* Disable interrupts */
priv->ier = 0;
up_serialout(priv, MPFS_UART_IER_OFFSET, 0);
up_serialout(priv, MPFS_UART_IEM_OFFSET, 0);
/* Clear fifos */
up_serialout(priv, MPFS_UART_FCR_OFFSET,
(UART_FCR_RFIFOR | UART_FCR_XFIFOR));
/* set filter to minimum value */
up_serialout(priv, MPFS_UART_GFR_OFFSET, 0);
/* set default TX time guard */
up_serialout(priv, MPFS_UART_TTG_OFFSET, 0);
/* Configure the UART line format and speed. */
up_set_format(dev);
/* Configure the FIFOs */
@ -582,6 +662,8 @@ static void up_shutdown(struct uart_dev_s *dev)
/* Disable interrupts */
up_disableuartint(priv, NULL);
up_enable_uart(priv, false);
}
/****************************************************************************
@ -749,7 +831,108 @@ static int uart_interrupt(int irq, void *context, void *arg)
static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
{
return -ENOTTY;
#if defined(CONFIG_SERIAL_TERMIOS) || defined(CONFIG_SERIAL_TIOCSERGSTRUCT)
struct inode *inode = filep->f_inode;
struct uart_dev_s *dev = inode->i_private;
struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
#endif
int ret = OK;
switch (cmd)
{
#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT
case TIOCSERGSTRUCT:
{
struct up_dev_s *user = (struct up_dev_s *)arg;
if (!user)
{
ret = -EINVAL;
}
else
{
memcpy(user, dev, sizeof(struct up_dev_s));
}
}
break;
#endif
#ifdef CONFIG_SERIAL_TERMIOS
case TCGETS:
{
struct termios *termiosp = (struct termios *)arg;
if (!termiosp)
{
ret = -EINVAL;
break;
}
#ifdef CONFIG_SERIAL_OFLOWCONTROL
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#endif
termiosp->c_cflag =
((priv->parity != 0) ? PARENB : 0) |
((priv->parity == 1) ? PARODD : 0) |
((priv->stopbits2) ? CSTOPB : 0) |
((priv->bits == 5) ? CS5 : 0) |
((priv->bits == 6) ? CS6 : 0) |
((priv->bits == 7) ? CS7 : 0) |
((priv->bits == 8) ? CS8 : 0);
cfsetispeed(termiosp, priv->baud);
}
break;
case TCSETS:
{
struct termios *termiosp = (struct termios *)arg;
if (!termiosp)
{
ret = -EINVAL;
break;
}
if (termiosp->c_cflag & PARENB)
{
priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
}
else
{
priv->parity = 0;
}
priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0;
priv->bits = (termiosp->c_cflag & CS5) ? 5 : 0;
priv->bits = (termiosp->c_cflag & CS6) ? 6 : 0;
priv->bits = (termiosp->c_cflag & CS7) ? 7 : 0;
priv->bits = (termiosp->c_cflag & CS8) ? 8 : 0;
/* Note that only cfgetispeed is used because we have knowledge
* that only one speed is supported.
*/
priv->baud = cfgetispeed(termiosp);
/* Effect the changes immediately - note that we do not implement
* TCSADRAIN / TCSAFLUSH
*/
up_set_format(dev);
}
break;
#endif /* CONFIG_SERIAL_TERMIOS */
default:
ret = -ENOTTY;
break;
}
return ret;
}
/****************************************************************************
@ -869,7 +1052,7 @@ static void up_txint(struct uart_dev_s *dev, bool enable)
* Name: up_txready
*
* Description:
* Return true if the tranmsit data register is not full
* Return true if the transmit data register is not full
*
****************************************************************************/
@ -883,7 +1066,7 @@ static bool up_txready(struct uart_dev_s *dev)
* Name: up_txempty
*
* Description:
* Return true if the tranmsit data register is empty
* Return true if the transmit data register is empty
*
****************************************************************************/
@ -905,9 +1088,8 @@ static bool up_txempty(struct uart_dev_s *dev)
* 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 riscv_serialinit. NOTE: This function depends on GPIO pin
* configuration performed in up_consoleinit() and main clock iniialization
* performed in up_clkinitialize().
* before riscv_serialinit. NOTE: This function depends on
* main clock initialization performed in up_clkinitialize().
*
****************************************************************************/