drivers/serial/pl011: add support of uart0/2/3 port

Signed-off-by: chao an <anchao@lixiang.com>
This commit is contained in:
chao an 2024-01-11 14:15:45 +08:00 committed by Alin Jerpelea
parent 5f51aba1be
commit 1dd9f64287
2 changed files with 342 additions and 143 deletions

View File

@ -10,51 +10,59 @@ config UART0_PL011
select UART0_SERIALDRIVER
default n
if UART0_PL011
config UART0_BASE
hex "UART0 base address"
config UART0_IRQ
int "PL011 UART0 IRQ number"
endif # UART0_PL011
config UART1_PL011
bool "UART1 PL011"
select UART1_SERIALDRIVER
default n
if UART1_PL011
config UART1_BASE
hex "UART1 base address"
config UART1_IRQ
int "PL011 UART1 IRQ number"
endif # UART1_PL011
config UART2_PL011
bool "UART2 PL011"
select UART2_SERIALDRIVER
default n
if UART2_PL011
config UART2_BASE
hex "UART2 base address"
config UART2_IRQ
int "PL011 UART2 IRQ number"
endif # UART2_PL011
config UART3_PL011
bool "UART3 PL011"
select UART3_SERIALDRIVER
default n
config UART0_BASE
hex "UART0 base address"
depends on UART0_PL011
config UART1_BASE
hex "UART1 base address"
depends on UART1_PL011
config UART2_BASE
hex "UART2 base address"
depends on UART2_PL011
if UART3_PL011
config UART3_BASE
hex "UART3 base address"
depends on UART3_PL011
config UART0_IRQ
int "PL011 UART0 IRQ number"
depends on UART0_PL011
config UART1_IRQ
int "PL011 UART1 IRQ number"
depends on UART1_PL011
config UART2_IRQ
int "PL011 UART2 IRQ number"
depends on UART2_PL011
config UART3_IRQ
int "PL011 UART3 IRQ number"
depends on UART3_PL011
endif # UART3_PL011
endif # UART_PL011

View File

@ -59,10 +59,16 @@
/* First pick the console and ttys0. This could be any of UART1-5 */
#if defined(CONFIG_UART1_SERIAL_CONSOLE)
# define CONSOLE_DEV g_uart1port /* UART1 is console */
# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */
# define UART1_ASSIGNED 1
#if defined(CONFIG_UART0_SERIAL_CONSOLE) && defined(CONFIG_UART0_PL011)
# define HAVE_PL011_CONSOLE 1
#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_UART1_PL011)
# define HAVE_PL011_CONSOLE 1
#elif defined(CONFIG_UART2_SERIAL_CONSOLE) && defined(CONFIG_UART2_PL011)
# define HAVE_PL011_CONSOLE 1
#elif defined(CONFIG_UART3_SERIAL_CONSOLE) && defined(CONFIG_UART3_PL011)
# define HAVE_PL011_CONSOLE 1
#else
# undef HAVE_PL011_CONSOLE 1
#endif
#define PL011_BIT_MASK(x, y) (((2 << (x)) - 1) << (y))
@ -220,9 +226,263 @@ struct pl011_uart_port_s
struct pl011_data data;
struct pl011_config config;
unsigned int irq_num;
bool is_console;
};
static int pl011_setup(struct uart_dev_s *dev);
static void pl011_shutdown(struct uart_dev_s *dev);
static int pl011_attach(struct uart_dev_s *dev);
static void pl011_detach(struct uart_dev_s *dev);
static int pl011_ioctl(struct file *filep, int cmd, unsigned long arg);
static int pl011_receive(struct uart_dev_s *dev, unsigned int *status);
static void pl011_rxint(struct uart_dev_s *dev, bool enable);
static bool pl011_rxavailable(struct uart_dev_s *dev);
static void pl011_send(struct uart_dev_s *dev, int ch);
static void pl011_txint(struct uart_dev_s *dev, bool enable);
static bool pl011_txready(struct uart_dev_s *dev);
static bool pl011_txempty(struct uart_dev_s *dev);
/***************************************************************************
* Private Data
***************************************************************************/
/* Serial driver UART operations */
static const struct uart_ops_s g_uart_ops =
{
.setup = pl011_setup,
.shutdown = pl011_shutdown,
.attach = pl011_attach,
.detach = pl011_detach,
.ioctl = pl011_ioctl,
.receive = pl011_receive,
.rxint = pl011_rxint,
.rxavailable = pl011_rxavailable,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rxflowcontrol = NULL,
#endif
.send = pl011_send,
.txint = pl011_txint,
.txready = pl011_txready,
.txempty = pl011_txempty,
};
/* I/O buffers */
#ifdef CONFIG_UART0_PL011
static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE];
static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE];
#endif
#ifdef CONFIG_UART1_PL011
static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE];
static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE];
#endif
#ifdef CONFIG_UART2_PL011
static char g_uart2rxbuffer[CONFIG_UART2_RXBUFSIZE];
static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE];
#endif
#ifdef CONFIG_UART3_PL011
static char g_uart3rxbuffer[CONFIG_UART3_RXBUFSIZE];
static char g_uart3txbuffer[CONFIG_UART3_TXBUFSIZE];
#endif
/* This describes the state of the uart0 port. */
#ifdef CONFIG_UART0_PL011
static struct pl011_uart_port_s g_uart0priv =
{
.data =
{
.baud_rate = CONFIG_UART0_BAUD,
.sbsa = false,
},
.config =
{
.uart = (volatile struct pl011_regs *)CONFIG_UART0_BASE,
.sys_clk_freq = 24000000,
},
.irq_num = CONFIG_UART0_IRQ,
};
/* I/O buffers */
static struct uart_dev_s 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 /* CONFIG_UART0_PL011 */
/* This describes the state of the uart1 port. */
#ifdef CONFIG_UART1_PL011
static struct pl011_uart_port_s g_uart1priv =
{
.data =
{
.baud_rate = CONFIG_UART1_BAUD,
.sbsa = false,
},
.config =
{
.uart = (volatile struct pl011_regs *)CONFIG_UART1_BASE,
.sys_clk_freq = 24000000,
},
.irq_num = CONFIG_UART1_IRQ,
};
/* I/O buffers */
static struct uart_dev_s 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 /* CONFIG_UART1_PL011 */
/* This describes the state of the uart2 port. */
#ifdef CONFIG_UART2_PL011
static struct pl011_uart_port_s g_uart2priv =
{
.data =
{
.baud_rate = CONFIG_UART2_BAUD,
.sbsa = false,
},
.config =
{
.uart = (volatile struct pl011_regs *)CONFIG_UART2_BASE,
.sys_clk_freq = 24000000,
},
.irq_num = CONFIG_UART2_IRQ,
};
/* I/O buffers */
static struct uart_dev_s 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 /* CONFIG_UART2_PL011 */
/* This describes the state of the uart3 port. */
#ifdef CONFIG_UART3_PL011
static struct pl011_uart_port_s g_uart3priv =
{
.data =
{
.baud_rate = CONFIG_UART3_BAUD,
.sbsa = false,
},
.config =
{
.uart = (volatile struct pl011_regs *)CONFIG_UART3_BASE,
.sys_clk_freq = 24000000,
},
.irq_num = CONFIG_UART3_IRQ,
};
/* I/O buffers */
static struct uart_dev_s g_uart3port =
{
.recv =
{
.size = CONFIG_UART3_RXBUFSIZE,
.buffer = g_uart3rxbuffer,
},
.xmit =
{
.size = CONFIG_UART3_TXBUFSIZE,
.buffer = g_uart3txbuffer,
},
.ops = &g_uart_ops,
.priv = &g_uart3priv,
};
#endif /* CONFIG_UART3_PL011 */
#if defined(CONFIG_UART0_SERIAL_CONSOLE)
# define CONSOLE_DEV g_uart0port /* UART0 is console */
#elif defined(CONFIG_UART1_SERIAL_CONSOLE)
# define CONSOLE_DEV g_uart1port /* UART1 is console */
#elif defined(CONFIG_UART2_SERIAL_CONSOLE)
# define CONSOLE_DEV g_uart2port /* UART2 is console */
#elif defined(CONFIG_UART3_SERIAL_CONSOLE)
# define CONSOLE_DEV g_uart3port /* UART3 is console */
#endif
#ifdef CONFIG_UART0_PL011
# define TTYS0_DEV g_uart0port
#endif
#ifdef CONFIG_UART1_PL011
# define TTYS1_DEV g_uart1port
#endif
#ifdef CONFIG_UART2_PL011
# define TTYS2_DEV g_uart2port
#endif
#ifdef CONFIG_UART3_PL011
# define TTYS3_DEV g_uart3port
#endif
/***************************************************************************
* Private Functions
***************************************************************************/
@ -350,7 +610,7 @@ static int pl011_irq_rx_ready(const struct pl011_uart_port_s *sport)
static bool pl011_txready(struct uart_dev_s *dev)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
const struct pl011_config *config = &sport->config;
struct pl011_data *data = &sport->data;
@ -373,7 +633,7 @@ static bool pl011_txready(struct uart_dev_s *dev)
static bool pl011_txempty(struct uart_dev_s *dev)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
return pl011_irq_tx_complete(sport);
}
@ -388,7 +648,7 @@ static bool pl011_txempty(struct uart_dev_s *dev)
static void pl011_send(struct uart_dev_s *dev, int ch)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
const struct pl011_config *config = &sport->config;
config->uart->dr = ch;
@ -404,7 +664,7 @@ static void pl011_send(struct uart_dev_s *dev, int ch)
static bool pl011_rxavailable(struct uart_dev_s *dev)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
const struct pl011_config *config = &sport->config;
struct pl011_data *data = &sport->data;
@ -428,7 +688,7 @@ static bool pl011_rxavailable(struct uart_dev_s *dev)
static void pl011_rxint(struct uart_dev_s *dev, bool enable)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
if (enable)
{
@ -450,7 +710,7 @@ static void pl011_rxint(struct uart_dev_s *dev, bool enable)
static void pl011_txint(struct uart_dev_s *dev, bool enable)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
irqstate_t flags;
flags = enter_critical_section();
@ -485,7 +745,7 @@ static void pl011_txint(struct uart_dev_s *dev, bool enable)
static int pl011_receive(struct uart_dev_s *dev, unsigned int *status)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
const struct pl011_config *config = &sport->config;
unsigned int rx;
@ -537,13 +797,13 @@ static int pl011_ioctl(struct file *filep, int cmd, unsigned long arg)
static int pl011_irq_handler(int irq, void *context, void *arg)
{
struct uart_dev_s *dev = (struct uart_dev_s *)arg;
struct uart_dev_s *dev = arg;
struct pl011_uart_port_s *sport;
UNUSED(irq);
UNUSED(context);
DEBUGASSERT(dev != NULL && dev->priv != NULL);
sport = (struct pl011_uart_port_s *)dev->priv;
sport = dev->priv;
if (pl011_irq_rx_ready(sport))
{
@ -570,7 +830,7 @@ static int pl011_irq_handler(int irq, void *context, void *arg)
static void pl011_detach(struct uart_dev_s *dev)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
up_disable_irq(sport->irq_num);
irq_detach(sport->irq_num);
@ -599,7 +859,7 @@ static int pl011_attach(struct uart_dev_s *dev)
struct pl011_data *data;
int ret;
sport = (struct pl011_uart_port_s *)dev->priv;
sport = dev->priv;
data = &sport->data;
ret = irq_attach(sport->irq_num, pl011_irq_handler, dev);
@ -638,7 +898,7 @@ static void pl011_shutdown(struct uart_dev_s *dev)
static int pl011_setup(struct uart_dev_s *dev)
{
struct pl011_uart_port_s *sport = (struct pl011_uart_port_s *)dev->priv;
struct pl011_uart_port_s *sport = dev->priv;
const struct pl011_config *config = &sport->config;
struct pl011_data *data = &sport->data;
int ret;
@ -698,74 +958,6 @@ static int pl011_setup(struct uart_dev_s *dev)
return 0;
}
/***************************************************************************
* Private Data
***************************************************************************/
/* Serial driver UART operations */
static const struct uart_ops_s g_uart_ops =
{
.setup = pl011_setup,
.shutdown = pl011_shutdown,
.attach = pl011_attach,
.detach = pl011_detach,
.ioctl = pl011_ioctl,
.receive = pl011_receive,
.rxint = pl011_rxint,
.rxavailable = pl011_rxavailable,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rxflowcontrol = NULL,
#endif
.send = pl011_send,
.txint = pl011_txint,
.txready = pl011_txready,
.txempty = pl011_txempty,
};
/* This describes the state of the uart1 port. */
static struct pl011_uart_port_s g_uart1priv =
{
.data =
{
.baud_rate = CONFIG_UART1_BAUD,
.sbsa = false,
},
.config =
{
.uart = (volatile struct pl011_regs *)CONFIG_UART1_BASE,
.sys_clk_freq = 24000000,
},
.irq_num = CONFIG_UART1_IRQ,
.is_console = 1,
};
/* I/O buffers */
static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE];
static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE];
static struct uart_dev_s 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,
};
/***************************************************************************
* Public Functions
***************************************************************************/
@ -790,17 +982,44 @@ void pl011_earlyserialinit(void)
}
/***************************************************************************
* Name: up_putc
* Name: pl011_serialinit
*
* Description:
* Provide priority, low-level access to support OS debug
* writes
* Register serial console and serial ports. This assumes that
* pl011_earlyserialinit was called previously.
*
***************************************************************************/
int up_putc(int ch)
void pl011_serialinit(void)
{
#ifdef CONSOLE_DEV
uart_register("/dev/console", &CONSOLE_DEV);
#endif
#ifdef TTYS0_DEV
uart_register("/dev/ttyS0", &TTYS0_DEV);
#endif
#ifdef TTYS1_DEV
uart_register("/dev/ttyS1", &TTYS1_DEV);
#endif
#ifdef TTYS2_DEV
uart_register("/dev/ttyS2", &TTYS2_DEV);
#endif
#ifdef TTYS3_DEV
uart_register("/dev/ttyS3", &TTYS3_DEV);
#endif
}
/***************************************************************************
* Name: up_putc
*
* Description:
* Provide priority, low-level access to support OS debug writes
*
***************************************************************************/
#ifdef HAVE_PL011_CONSOLE
int up_putc(int ch)
{
struct uart_dev_s *dev = &CONSOLE_DEV;
/* Check for LF */
@ -813,37 +1032,9 @@ int up_putc(int ch)
}
pl011_send(dev, ch);
#endif
return ch;
}
/***************************************************************************
* Name: pl011_serialinit
*
* Description:
* see nuttx/serial/uart_pl011.h
*
***************************************************************************/
void pl011_serialinit(void)
{
#ifdef CONSOLE_DEV
int ret;
ret = uart_register("/dev/console", &CONSOLE_DEV);
if (ret < 0)
{
sinfo("error at register dev/console, ret =%d\n", ret);
}
ret = uart_register("/dev/ttyS0", &TTYS0_DEV);
if (ret < 0)
{
sinfo("error at register dev/ttyS0, ret =%d\n", ret);
}
#endif
}
#endif /* USE_SERIALDRIVER */
#endif /* CONFIG_UART_PL011 */