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
@@ -57,14 +57,6 @@
#define MPFS_UART_RTO_OFFSET 0x004C /* UART Receiver time-out register */ #define MPFS_UART_RTO_OFFSET 0x004C /* UART Receiver time-out register */
#define MPFS_UART_ADR_OFFSET 0x0050 /* UART Address 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 *******************************************/ /* Register bit field definitions *******************************************/
/* UART Receive Buffer Register */ /* 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_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_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_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 #define UART_IER_ALLIE 0x0000008f
/* UART Interrupt Identity Register */ /* UART Interrupt Identity Register */
+25 -5
View File
@@ -48,6 +48,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART0_BITS # define MPFS_CONSOLE_BITS CONFIG_UART0_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART0_PARITY # define MPFS_CONSOLE_PARITY CONFIG_UART0_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART0_2STOP # 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 # define HAVE_UART
#elif defined(CONFIG_UART1_SERIAL_CONSOLE) #elif defined(CONFIG_UART1_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART1_BASE # define MPFS_CONSOLE_BASE MPFS_UART1_BASE
@@ -55,6 +57,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART1_BITS # define MPFS_CONSOLE_BITS CONFIG_UART1_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART1_PARITY # define MPFS_CONSOLE_PARITY CONFIG_UART1_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART1_2STOP # 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 # define HAVE_UART
#elif defined(CONFIG_UART2_SERIAL_CONSOLE) #elif defined(CONFIG_UART2_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART2_BASE # define MPFS_CONSOLE_BASE MPFS_UART2_BASE
@@ -62,6 +66,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART2_BITS # define MPFS_CONSOLE_BITS CONFIG_UART2_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART2_PARITY # define MPFS_CONSOLE_PARITY CONFIG_UART2_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART2_2STOP # 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 # define HAVE_UART
# elif defined(CONFIG_UART3_SERIAL_CONSOLE) # elif defined(CONFIG_UART3_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART3_BASE # define MPFS_CONSOLE_BASE MPFS_UART3_BASE
@@ -69,6 +75,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART3_BITS # define MPFS_CONSOLE_BITS CONFIG_UART3_BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART3_PARITY # define MPFS_CONSOLE_PARITY CONFIG_UART3_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART3_2STOP # 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 # define HAVE_UART
# elif defined(CONFIG_UART4_SERIAL_CONSOLE) # elif defined(CONFIG_UART4_SERIAL_CONSOLE)
# define MPFS_CONSOLE_BASE MPFS_UART4_BASE # define MPFS_CONSOLE_BASE MPFS_UART4_BASE
@@ -76,6 +84,8 @@
# define MPFS_CONSOLE_BITS CONFIG_UART4BITS # define MPFS_CONSOLE_BITS CONFIG_UART4BITS
# define MPFS_CONSOLE_PARITY CONFIG_UART4_PARITY # define MPFS_CONSOLE_PARITY CONFIG_UART4_PARITY
# define MPFS_CONSOLE_2STOP CONFIG_UART4_2STOP # 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 # define HAVE_UART
# elif defined(HAVE_UART) # elif defined(HAVE_UART)
# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" # error "No CONFIG_UARTn_SERIAL_CONSOLE Setting"
@@ -178,14 +188,24 @@ void mpfs_lowsetup(void)
/* Enable and configure the selected console device */ /* 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) #if defined(HAVE_SERIAL_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG)
uint32_t lcr = 0; 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) switch (MPFS_CONSOLE_BITS)
{ {
case 5: case 5:
+222 -40
View File
@@ -35,17 +35,21 @@
#include <nuttx/irq.h> #include <nuttx/irq.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/fs/ioctl.h>
#include <nuttx/serial/serial.h> #include <nuttx/serial/serial.h>
#include <arch/board/board.h> #ifdef CONFIG_SERIAL_TERMIOS
# include <termios.h>
#endif
#include "riscv_arch.h" #include <arch/board/board.h>
#include "riscv_internal.h"
#include "chip.h" #include "chip.h"
#include "mpfs.h" #include "mpfs.h"
#include "mpfs_config.h" #include "mpfs_config.h"
#include "mpfs_clockconfig.h" #include "mpfs_clockconfig.h"
#include "riscv_arch.h"
#include "riscv_internal.h"
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
@@ -341,7 +345,7 @@ static uart_dev_t g_uart4port =
}, },
.xmit = .xmit =
{ {
.size = CONFIG_UART3_TXBUFSIZE, .size = CONFIG_UART4_TXBUFSIZE,
.buffer = g_uart4txbuffer, .buffer = g_uart4txbuffer,
}, },
.ops = &g_uart_ops, .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); 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 * 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: * Description:
* Configure the UART baud, bits, parity, etc. This method is called the * Set the serial line format and speed.
* first time that the serial port is opened.
* *
****************************************************************************/ ****************************************************************************/
static int up_setup(struct uart_dev_s *dev)
{
#ifndef CONFIG_SUPPRESS_UART_CONFIG #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; struct up_dev_s *priv = (struct up_dev_s *)dev->priv;
uint32_t lcr; uint32_t lcr = 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);
/* 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);
/* Set up the LCR */ /* Set up the LCR */
lcr = 0;
switch (priv->bits) switch (priv->bits)
{ {
case 5: case 5:
@@ -550,6 +587,49 @@ static int up_setup(struct uart_dev_s *dev)
/* Clear DLAB */ /* Clear DLAB */
up_serialout(priv, MPFS_UART_LCR_OFFSET, lcr); 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 */ /* Configure the FIFOs */
@@ -582,6 +662,8 @@ static void up_shutdown(struct uart_dev_s *dev)
/* Disable interrupts */ /* Disable interrupts */
up_disableuartint(priv, NULL); 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) 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 * Name: up_txready
* *
* Description: * 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 * Name: up_txempty
* *
* Description: * 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: * Description:
* Performs the low level UART initialization early in debug so that the * Performs the low level UART initialization early in debug so that the
* serial console will be available during bootup. This must be called * serial console will be available during bootup. This must be called
* before riscv_serialinit. NOTE: This function depends on GPIO pin * before riscv_serialinit. NOTE: This function depends on
* configuration performed in up_consoleinit() and main clock iniialization * main clock initialization performed in up_clkinitialize().
* performed in up_clkinitialize().
* *
****************************************************************************/ ****************************************************************************/