drivers: prepare 16550 UART driver to support PCI
prepare 16550 UART driver to support PCI: - [breaking change] change argument of uart_ioctl() from `struct file *filep` to `FAR struct u16550_s *priv` Also fix moxart_16550.c build related to this change - [breaking change] change argument of uart_getreg() and uart_putreg from `uart_addrwidth_t base` to `FAR struct u16550_s *priv` Also fix arch/x86/src/qemu/qemu_serial.c and arch/x86_64/src/intel64/intel64_serial.c related to this change - [breaking change] change argument of uart_dmachan() from `uart_addrwidth_t base` to `FAR struct u16550_s *priv` - move `struct u16550_s` to public header - generalize UART_XXX_OFFSET so we can use it with any register increment - make u16550_bind(), u16550_interrupt(), u16550_interrupt() public - remove arch/or1k/src/common/or1k_uart.c and use common 16550 MIMO interfacve - change irq type in `struct u16550_s` from uint8_t to int to match MSI API Signed-off-by: p-szafonimateusz <p-szafonimateusz@xiaomi.com>
This commit is contained in:
parent
c7e8fd43a4
commit
ceb2921d79
@ -69,15 +69,12 @@ void uart_decodeirq(int irq, void *context)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_IOCTL
|
||||
int uart_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||
int uart_ioctl(FAR struct u16550_s *priv, int cmd, unsigned long arg)
|
||||
{
|
||||
struct inode *inode = filep->f_inode;
|
||||
struct uart_dev_s *dev = inode->i_private;
|
||||
struct u16550_s *priv = (struct u16550_s *)dev->priv;
|
||||
int ret = -ENOTTY;
|
||||
uint32_t vmode;
|
||||
unsigned int opmode;
|
||||
int bitm_off;
|
||||
int ret = -ENOTTY;
|
||||
uint32_t vmode;
|
||||
unsigned int opmode;
|
||||
int bitm_off;
|
||||
|
||||
/* TODO: calculate bit offset from UART_BASE address.
|
||||
* E.g.:
|
||||
|
@ -1,45 +0,0 @@
|
||||
/****************************************************************************
|
||||
* arch/or1k/src/common/or1k_uart.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <nuttx/serial/uart_16550.h>
|
||||
|
||||
#include "or1k_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
uart_datawidth_t uart_getreg(uart_addrwidth_t base, unsigned int offset)
|
||||
{
|
||||
return *(uint8_t *)(base + offset);
|
||||
}
|
||||
|
||||
void uart_putreg(uart_addrwidth_t base, unsigned int offset,
|
||||
uart_datawidth_t value)
|
||||
{
|
||||
*(uint8_t *)(base + offset) = value;
|
||||
}
|
@ -40,7 +40,6 @@ CMN_CSRCS = or1k_initialize.c \
|
||||
or1k_idle.c \
|
||||
or1k_irq.c \
|
||||
or1k_nputs.c \
|
||||
or1k_uart.c \
|
||||
or1k_timer.c \
|
||||
or1k_doirq.c \
|
||||
or1k_cpuinfo.c \
|
||||
|
@ -52,15 +52,15 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uart_datawidth_t uart_getreg(uart_addrwidth_t base, unsigned int offset)
|
||||
uart_datawidth_t uart_getreg(struct u16550_s *priv, unsigned int offset)
|
||||
{
|
||||
return inb(base + offset);
|
||||
return inb(priv->uartbase + offset);
|
||||
}
|
||||
|
||||
void uart_putreg(uart_addrwidth_t base,
|
||||
void uart_putreg(struct u16550_s *priv,
|
||||
unsigned int offset, uart_datawidth_t value)
|
||||
{
|
||||
outb(value, base + offset);
|
||||
outb(value, priv->uartbase + offset);
|
||||
}
|
||||
|
||||
#else /* USE_SERIALDRIVER */
|
||||
|
@ -52,12 +52,12 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uart_datawidth_t uart_getreg(uart_addrwidth_t base, unsigned int offset)
|
||||
uart_datawidth_t uart_getreg(struct u16550_s *priv, unsigned int offset)
|
||||
{
|
||||
return inb(base + offset);
|
||||
return inb(priv->uartbase + offset);
|
||||
}
|
||||
|
||||
void uart_putreg(uart_addrwidth_t base, unsigned int offset,
|
||||
void uart_putreg(struct u16550_s *priv, unsigned int offset,
|
||||
uart_datawidth_t value)
|
||||
{
|
||||
/* Intel x86 platform require OUT2 of MCR being set
|
||||
@ -69,7 +69,7 @@ void uart_putreg(uart_addrwidth_t base, unsigned int offset,
|
||||
value |= UART_MCR_OUT2;
|
||||
}
|
||||
|
||||
outb(value, base + offset);
|
||||
outb(value, priv->uartbase + offset);
|
||||
}
|
||||
|
||||
#else /* USE_SERIALDRIVER */
|
||||
|
@ -84,6 +84,7 @@ CONFIG_PTHREAD_STACK_DEFAULT=1024
|
||||
CONFIG_RAM_SIZE=4194304
|
||||
CONFIG_RAM_START=0x0000
|
||||
CONFIG_RAW_BINARY=y
|
||||
CONFIG_SERIAL_UART_ARCH_MMIO=y
|
||||
CONFIG_START_DAY=7
|
||||
CONFIG_START_MONTH=12
|
||||
CONFIG_START_YEAR=2012
|
||||
|
@ -39,75 +39,55 @@
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/clk/clk.h>
|
||||
#include <nuttx/dma/dma.h>
|
||||
#include <nuttx/serial/serial.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
#include <nuttx/serial/uart_16550.h>
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
#if defined(CONFIG_16550_UART0_DMA) || defined(CONFIG_16550_UART1_DMA) \
|
||||
|| defined(CONFIG_16550_UART2_DMA) || defined(CONFIG_16550_UART3_DMA)
|
||||
# define HAVE_16550_UART_DMA 1
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_16550_UART
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Are any UARTs enabled? */
|
||||
|
||||
#undef HAVE_16550_UART
|
||||
#if defined(CONFIG_16550_UART0) || defined(CONFIG_16550_UART1) \
|
||||
|| defined(CONFIG_16550_UART2) || defined(CONFIG_16550_UART3)
|
||||
# define HAVE_16550_UART 1
|
||||
#endif
|
||||
|
||||
/* Timeout for UART Busy Wait, in milliseconds */
|
||||
|
||||
#define UART_TIMEOUT_MS 100
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
/* Default getreg/putreg operations */
|
||||
|
||||
struct u16550_s
|
||||
{
|
||||
uart_addrwidth_t uartbase; /* Base address of UART registers */
|
||||
#ifdef HAVE_16550_UART_DMA
|
||||
int32_t dmatx;
|
||||
FAR struct dma_chan_s *chantx;
|
||||
int32_t dmarx;
|
||||
FAR struct dma_chan_s *chanrx;
|
||||
FAR char *dmarxbuf;
|
||||
size_t dmarxsize;
|
||||
volatile size_t dmarxhead;
|
||||
volatile size_t dmarxtail;
|
||||
int32_t dmarxtimeout;
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
# define u16550_getreg u16550_mmio_getreg
|
||||
# define u16550_putreg u16550_mmio_putreg
|
||||
#else
|
||||
# define u16550_getreg uart_getreg
|
||||
# define u16550_putreg uart_putreg
|
||||
#endif
|
||||
#if !defined(CONFIG_16550_SUPRESS_CONFIG) || defined(HAVE_16550_UART_DMA)
|
||||
uint32_t baud; /* Configured baud */
|
||||
uint32_t uartclk; /* UART clock frequency */
|
||||
#endif
|
||||
#ifdef CONFIG_CLK
|
||||
FAR const char *clk_name; /* UART clock name */
|
||||
FAR struct clk_s *mclk; /* UART clock descriptor */
|
||||
#endif
|
||||
uart_datawidth_t ier; /* Saved IER value */
|
||||
uint8_t irq; /* IRQ associated with this UART */
|
||||
#ifndef CONFIG_16550_SUPRESS_CONFIG
|
||||
uint8_t parity; /* 0=none, 1=odd, 2=even */
|
||||
uint8_t bits; /* Number of bits (7 or 8) */
|
||||
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
|
||||
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
|
||||
bool flow; /* flow control (RTS/CTS) enabled */
|
||||
#endif
|
||||
#endif
|
||||
uart_datawidth_t rxtrigger; /* RX trigger level */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
static uart_datawidth_t u16550_mmio_getreg(FAR struct u16550_s *priv,
|
||||
unsigned int offset);
|
||||
static void u16550_mmio_putreg(FAR struct u16550_s *priv,
|
||||
unsigned int offset,
|
||||
uart_datawidth_t value);
|
||||
#endif
|
||||
|
||||
static int u16550_setup(FAR struct uart_dev_s *dev);
|
||||
static void u16550_shutdown(FAR struct uart_dev_s *dev);
|
||||
static int u16550_attach(FAR struct uart_dev_s *dev);
|
||||
static void u16550_detach(FAR struct uart_dev_s *dev);
|
||||
static int u16550_interrupt(int irq, FAR void *context, FAR void *arg);
|
||||
static int u16550_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||
static int u16550_receive(FAR struct uart_dev_s *dev, unsigned int *status);
|
||||
static void u16550_rxint(FAR struct uart_dev_s *dev, bool enable);
|
||||
@ -133,6 +113,21 @@ static bool u16550_txempty(FAR struct uart_dev_s *dev);
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_16550_UART
|
||||
static const struct u16550_ops_s g_u16550_ops =
|
||||
{
|
||||
.isr = u16550_interrupt,
|
||||
.getreg = u16550_getreg,
|
||||
.putreg = u16550_putreg,
|
||||
# ifdef CONFIG_SERIAL_UART_ARCH_IOCTL
|
||||
.ioctl = uart_ioctl,
|
||||
# endif
|
||||
# ifdef HAVE_16550_UART_DMA
|
||||
.dmachan = uart_dmachan,
|
||||
# endif
|
||||
};
|
||||
#endif
|
||||
|
||||
static const struct uart_ops_s g_uart_ops =
|
||||
{
|
||||
.setup = u16550_setup,
|
||||
@ -197,7 +192,9 @@ static char g_uart3dmarxbuf[CONFIG_16550_UART3_DMA_RXBUFSIZE];
|
||||
#ifdef CONFIG_16550_UART0
|
||||
static struct u16550_s g_uart0priv =
|
||||
{
|
||||
.ops = &g_u16550_ops,
|
||||
.uartbase = CONFIG_16550_UART0_BASE,
|
||||
.regincr = CONFIG_16550_REGINCR,
|
||||
#ifdef CONFIG_16550_UART0_DMA
|
||||
.dmatx = CONFIG_16550_UART0_DMA_TX,
|
||||
.dmarx = CONFIG_16550_UART0_DMA_RX,
|
||||
@ -251,7 +248,9 @@ static uart_dev_t g_uart0port =
|
||||
#ifdef CONFIG_16550_UART1
|
||||
static struct u16550_s g_uart1priv =
|
||||
{
|
||||
.ops = &g_u16550_ops,
|
||||
.uartbase = CONFIG_16550_UART1_BASE,
|
||||
.regincr = CONFIG_16550_REGINCR,
|
||||
#ifdef CONFIG_16550_UART1_DMA
|
||||
.dmatx = CONFIG_16550_UART1_DMA_TX,
|
||||
.dmarx = CONFIG_16550_UART1_DMA_RX,
|
||||
@ -305,7 +304,9 @@ static uart_dev_t g_uart1port =
|
||||
#ifdef CONFIG_16550_UART2
|
||||
static struct u16550_s g_uart2priv =
|
||||
{
|
||||
.ops = &g_u16550_ops,
|
||||
.uartbase = CONFIG_16550_UART2_BASE,
|
||||
.regincr = CONFIG_16550_REGINCR,
|
||||
#ifdef CONFIG_16550_UART2_DMA
|
||||
.dmatx = CONFIG_16550_UART2_DMA_TX,
|
||||
.dmarx = CONFIG_16550_UART2_DMA_RX,
|
||||
@ -359,7 +360,9 @@ static uart_dev_t g_uart2port =
|
||||
#ifdef CONFIG_16550_UART3
|
||||
static struct u16550_s g_uart3priv =
|
||||
{
|
||||
.ops = &g_u16550_ops,
|
||||
.uartbase = CONFIG_16550_UART3_BASE,
|
||||
.regincr = CONFIG_16550_REGINCR,
|
||||
#ifdef CONFIG_16550_UART3_DMA
|
||||
.dmatx = CONFIG_16550_UART3_DMA_TX,
|
||||
.dmarx = CONFIG_16550_UART3_DMA_RX,
|
||||
@ -607,6 +610,31 @@ static uart_dev_t g_uart3port =
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
/****************************************************************************
|
||||
* Name: u16550_mmio_getreg
|
||||
****************************************************************************/
|
||||
|
||||
static uart_datawidth_t u16550_mmio_getreg(FAR struct u16550_s *priv,
|
||||
unsigned int offset)
|
||||
{
|
||||
uintptr_t addr = priv->uartbase + offset;
|
||||
return *((FAR volatile uart_datawidth_t *)addr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_mmio_putreg
|
||||
****************************************************************************/
|
||||
|
||||
static void u16550_mmio_putreg(FAR struct u16550_s *priv,
|
||||
unsigned int offset,
|
||||
uart_datawidth_t value)
|
||||
{
|
||||
uintptr_t addr = priv->uartbase + offset;
|
||||
*((FAR volatile uart_datawidth_t *)addr) = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_serialin
|
||||
****************************************************************************/
|
||||
@ -614,11 +642,10 @@ static uart_dev_t g_uart3port =
|
||||
static inline uart_datawidth_t u16550_serialin(FAR struct u16550_s *priv,
|
||||
int offset)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
return *((FAR volatile uart_datawidth_t *)priv->uartbase + offset);
|
||||
#else
|
||||
return uart_getreg(priv->uartbase, offset);
|
||||
#endif
|
||||
/* Get correct offset */
|
||||
|
||||
offset *= (priv->regincr * sizeof(uart_datawidth_t));
|
||||
return priv->ops->getreg(priv, offset);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -628,11 +655,10 @@ static inline uart_datawidth_t u16550_serialin(FAR struct u16550_s *priv,
|
||||
static inline void u16550_serialout(FAR struct u16550_s *priv, int offset,
|
||||
uart_datawidth_t value)
|
||||
{
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
*((FAR volatile uart_datawidth_t *)priv->uartbase + offset) = value;
|
||||
#else
|
||||
uart_putreg(priv->uartbase, offset, value);
|
||||
#endif
|
||||
/* Get correct offset */
|
||||
|
||||
offset *= (priv->regincr * sizeof(uart_datawidth_t));
|
||||
priv->ops->putreg(priv, offset, value);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_16550_WAIT_LCR
|
||||
@ -759,6 +785,13 @@ static int u16550_setup(FAR struct uart_dev_s *dev)
|
||||
uint32_t mcr;
|
||||
#endif
|
||||
|
||||
if (priv->uartbase == 0)
|
||||
{
|
||||
/* Device must be initialized */
|
||||
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* Clear fifos */
|
||||
|
||||
u16550_serialout(priv, UART_FCR_OFFSET,
|
||||
@ -930,7 +963,7 @@ static int u16550_attach(struct uart_dev_s *dev)
|
||||
|
||||
/* Attach and enable the IRQ */
|
||||
|
||||
ret = irq_attach(priv->irq, u16550_interrupt, dev);
|
||||
ret = irq_attach(priv->irq, priv->ops->isr, dev);
|
||||
#ifndef CONFIG_ARCH_NOINTC
|
||||
if (ret == OK)
|
||||
{
|
||||
@ -974,7 +1007,7 @@ static void u16550_detach(FAR struct uart_dev_s *dev)
|
||||
#endif
|
||||
|
||||
up_disable_irq(priv->irq);
|
||||
irq_detach(priv->irq);
|
||||
irqchain_detach(priv->irq, priv->ops->isr, dev);
|
||||
|
||||
#ifdef CONFIG_CLK
|
||||
/* Clk disaable */
|
||||
@ -986,109 +1019,6 @@ static void u16550_detach(FAR struct uart_dev_s *dev)
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_interrupt
|
||||
*
|
||||
* Description:
|
||||
* This is the UART interrupt handler. It will be invoked when an
|
||||
* interrupt is received on the 'irq'. It should call uart_xmitchars or
|
||||
* uart_recvchars to perform the appropriate data transfers. The
|
||||
* interrupt handling logic must be able to map the 'arg' to the
|
||||
* appropriate uart_dev_s structure in order to call these functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int u16550_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct uart_dev_s *dev = (struct uart_dev_s *)arg;
|
||||
FAR struct u16550_s *priv;
|
||||
uint32_t status;
|
||||
int passes;
|
||||
|
||||
DEBUGASSERT(dev != NULL && dev->priv != NULL);
|
||||
priv = (FAR struct u16550_s *)dev->priv;
|
||||
|
||||
/* Loop until there are no characters to be transferred or,
|
||||
* until we have been looping for a long time.
|
||||
*/
|
||||
|
||||
for (passes = 0; passes < 256; passes++)
|
||||
{
|
||||
/* Get the current UART status and check for loop
|
||||
* termination conditions
|
||||
*/
|
||||
|
||||
status = u16550_serialin(priv, UART_IIR_OFFSET);
|
||||
|
||||
/* The UART_IIR_INTSTATUS bit should be zero if there are pending
|
||||
* interrupts
|
||||
*/
|
||||
|
||||
if ((status & UART_IIR_INTSTATUS) != 0)
|
||||
{
|
||||
/* Break out of the loop when there is no longer a
|
||||
* pending interrupt
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle the interrupt by its interrupt ID field */
|
||||
|
||||
switch (status & UART_IIR_INTID_MASK)
|
||||
{
|
||||
/* Handle incoming, receive bytes (with or without timeout) */
|
||||
|
||||
case UART_IIR_INTID_RDA:
|
||||
case UART_IIR_INTID_CTI:
|
||||
{
|
||||
uart_recvchars(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle outgoing, transmit bytes */
|
||||
|
||||
case UART_IIR_INTID_THRE:
|
||||
{
|
||||
uart_xmitchars(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Just clear modem status interrupts (UART1 only) */
|
||||
|
||||
case UART_IIR_INTID_MSI:
|
||||
{
|
||||
/* Read the modem status register (MSR) to clear */
|
||||
|
||||
status = u16550_serialin(priv, UART_MSR_OFFSET);
|
||||
sinfo("MSR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Just clear any line status interrupts */
|
||||
|
||||
case UART_IIR_INTID_RLS:
|
||||
{
|
||||
/* Read the line status register (LSR) to clear */
|
||||
|
||||
status = u16550_serialin(priv, UART_LSR_OFFSET);
|
||||
sinfo("LSR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* There should be no other values */
|
||||
|
||||
default:
|
||||
{
|
||||
serr("ERROR: Unexpected IIR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_ioctl
|
||||
*
|
||||
@ -1105,7 +1035,7 @@ static int u16550_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_SERIAL_UART_ARCH_IOCTL
|
||||
ret = uart_ioctl(filep, cmd, arg);
|
||||
ret = priv->ops->ioctl(priv, cmd, arg);
|
||||
|
||||
if (ret != -ENOTTY)
|
||||
{
|
||||
@ -1538,7 +1468,7 @@ static void u16550_dmarxfree(FAR struct uart_dev_s *dev)
|
||||
|
||||
if (priv->chanrx == NULL)
|
||||
{
|
||||
priv->chanrx = uart_dmachan(priv->uartbase, priv->dmarx);
|
||||
priv->chanrx = priv->ops->dmachan(priv, priv->dmarx)
|
||||
if (priv->chanrx == NULL)
|
||||
{
|
||||
return; /* Fail to get DMA channel */
|
||||
@ -1589,7 +1519,7 @@ static void u16550_dmatxavail(FAR struct uart_dev_s *dev)
|
||||
|
||||
if (priv->chantx == NULL)
|
||||
{
|
||||
priv->chantx = uart_dmachan(priv->uartbase, priv->dmatx);
|
||||
priv->chantx = priv->ops->dmachan(priv, priv->dmatx);
|
||||
if (priv->chantx == NULL)
|
||||
{
|
||||
return; /* Fail to get DMA channel */
|
||||
@ -1692,22 +1622,6 @@ static bool u16550_txempty(struct uart_dev_s *dev)
|
||||
return ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_TEMT) != 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_putc
|
||||
*
|
||||
* Description:
|
||||
* Write one character to the UART (polled)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_16550_CONSOLE
|
||||
static void u16550_putc(FAR struct u16550_s *priv, int ch)
|
||||
{
|
||||
while ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) == 0);
|
||||
u16550_serialout(priv, UART_THR_OFFSET, (uart_datawidth_t)ch);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -1769,7 +1683,7 @@ void u16550_serialinit(void)
|
||||
* Name: up_putc
|
||||
*
|
||||
* Description:
|
||||
* Provide priority, low-level access to support OS debug writes
|
||||
* Provide priority, low-level access to support OS debug writes
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
@ -1793,4 +1707,145 @@ int up_putc(int ch)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_bind
|
||||
*
|
||||
* Description:
|
||||
* Bind 16550 compatible device with this driver.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int u16550_bind(FAR uart_dev_t *dev)
|
||||
{
|
||||
dev->ops = &g_uart_ops;
|
||||
|
||||
#ifdef CONFIG_16550_PCI_CONSOLE
|
||||
if (dev->isconsole)
|
||||
{
|
||||
/* Setup console device */
|
||||
|
||||
u16550_setup(dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_interrupt
|
||||
*
|
||||
* Description:
|
||||
* This is the UART interrupt handler. It will be invoked when an
|
||||
* interrupt is received on the 'irq'. It should call uart_xmitchars or
|
||||
* uart_recvchars to perform the appropriate data transfers. The
|
||||
* interrupt handling logic must be able to map the 'arg' to the
|
||||
* appropriate uart_dev_s structure in order to call these functions.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int u16550_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct uart_dev_s *dev = (struct uart_dev_s *)arg;
|
||||
FAR struct u16550_s *priv;
|
||||
uint32_t status;
|
||||
int passes;
|
||||
|
||||
DEBUGASSERT(dev != NULL && dev->priv != NULL);
|
||||
priv = (FAR struct u16550_s *)dev->priv;
|
||||
|
||||
/* Loop until there are no characters to be transferred or,
|
||||
* until we have been looping for a long time.
|
||||
*/
|
||||
|
||||
for (passes = 0; passes < 256; passes++)
|
||||
{
|
||||
/* Get the current UART status and check for loop
|
||||
* termination conditions
|
||||
*/
|
||||
|
||||
status = u16550_serialin(priv, UART_IIR_OFFSET);
|
||||
|
||||
/* The UART_IIR_INTSTATUS bit should be zero if there are pending
|
||||
* interrupts
|
||||
*/
|
||||
|
||||
if ((status & UART_IIR_INTSTATUS) != 0)
|
||||
{
|
||||
/* Break out of the loop when there is no longer a
|
||||
* pending interrupt
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle the interrupt by its interrupt ID field */
|
||||
|
||||
switch (status & UART_IIR_INTID_MASK)
|
||||
{
|
||||
/* Handle incoming, receive bytes (with or without timeout) */
|
||||
|
||||
case UART_IIR_INTID_RDA:
|
||||
case UART_IIR_INTID_CTI:
|
||||
{
|
||||
uart_recvchars(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Handle outgoing, transmit bytes */
|
||||
|
||||
case UART_IIR_INTID_THRE:
|
||||
{
|
||||
uart_xmitchars(dev);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Just clear modem status interrupts (UART1 only) */
|
||||
|
||||
case UART_IIR_INTID_MSI:
|
||||
{
|
||||
/* Read the modem status register (MSR) to clear */
|
||||
|
||||
status = u16550_serialin(priv, UART_MSR_OFFSET);
|
||||
sinfo("MSR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Just clear any line status interrupts */
|
||||
|
||||
case UART_IIR_INTID_RLS:
|
||||
{
|
||||
/* Read the line status register (LSR) to clear */
|
||||
|
||||
status = u16550_serialin(priv, UART_LSR_OFFSET);
|
||||
sinfo("LSR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
|
||||
/* There should be no other values */
|
||||
|
||||
default:
|
||||
{
|
||||
serr("ERROR: Unexpected IIR: %02"PRIx32"\n", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_putc
|
||||
*
|
||||
* Description:
|
||||
* Write one character to the UART (polled)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void u16550_putc(FAR struct u16550_s *priv, int ch)
|
||||
{
|
||||
while ((u16550_serialin(priv, UART_LSR_OFFSET) & UART_LSR_THRE) == 0);
|
||||
u16550_serialout(priv, UART_THR_OFFSET, (uart_datawidth_t)ch);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_16550_UART */
|
||||
|
@ -27,7 +27,8 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nuttx/serial/serial.h>
|
||||
|
||||
#ifdef CONFIG_16550_UART
|
||||
|
||||
@ -37,12 +38,10 @@
|
||||
|
||||
/* CONFIGURATION ************************************************************/
|
||||
|
||||
/* Are any UARTs enabled? */
|
||||
|
||||
#undef HAVE_UART
|
||||
#if defined(CONFIG_16550_UART0) || defined(CONFIG_16550_UART1) || \
|
||||
defined(CONFIG_16550_UART2) || defined(CONFIG_16550_UART3)
|
||||
# define HAVE_UART 1
|
||||
#undef HAVE_16550_UART_DMA
|
||||
#if defined(CONFIG_16550_UART0_DMA) || defined(CONFIG_16550_UART1_DMA) || \
|
||||
defined(CONFIG_16550_UART2_DMA) || defined(CONFIG_16550_UART3_DMA)
|
||||
# define HAVE_16550_UART_DMA 1
|
||||
#endif
|
||||
|
||||
/* We need to be told the address increment between registers and the
|
||||
@ -173,33 +172,20 @@
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define UART_RBR_INCR 0 /* (DLAB =0) Receiver Buffer Register */
|
||||
#define UART_THR_INCR 0 /* (DLAB =0) Transmit Holding Register */
|
||||
#define UART_DLL_INCR 0 /* (DLAB =1) Divisor Latch LSB */
|
||||
#define UART_DLM_INCR 1 /* (DLAB =1) Divisor Latch MSB */
|
||||
#define UART_IER_INCR 1 /* (DLAB =0) Interrupt Enable Register */
|
||||
#define UART_IIR_INCR 2 /* Interrupt ID Register */
|
||||
#define UART_FCR_INCR 2 /* FIFO Control Register */
|
||||
#define UART_LCR_INCR 3 /* Line Control Register */
|
||||
#define UART_MCR_INCR 4 /* Modem Control Register */
|
||||
#define UART_LSR_INCR 5 /* Line Status Register */
|
||||
#define UART_MSR_INCR 6 /* Modem Status Register */
|
||||
#define UART_SCR_INCR 7 /* Scratch Pad Register */
|
||||
#define UART_USR_INCR 31 /* UART Status Register */
|
||||
|
||||
#define UART_RBR_OFFSET (CONFIG_16550_REGINCR*UART_RBR_INCR)
|
||||
#define UART_THR_OFFSET (CONFIG_16550_REGINCR*UART_THR_INCR)
|
||||
#define UART_DLL_OFFSET (CONFIG_16550_REGINCR*UART_DLL_INCR)
|
||||
#define UART_DLM_OFFSET (CONFIG_16550_REGINCR*UART_DLM_INCR)
|
||||
#define UART_IER_OFFSET (CONFIG_16550_REGINCR*UART_IER_INCR)
|
||||
#define UART_IIR_OFFSET (CONFIG_16550_REGINCR*UART_IIR_INCR)
|
||||
#define UART_FCR_OFFSET (CONFIG_16550_REGINCR*UART_FCR_INCR)
|
||||
#define UART_LCR_OFFSET (CONFIG_16550_REGINCR*UART_LCR_INCR)
|
||||
#define UART_MCR_OFFSET (CONFIG_16550_REGINCR*UART_MCR_INCR)
|
||||
#define UART_LSR_OFFSET (CONFIG_16550_REGINCR*UART_LSR_INCR)
|
||||
#define UART_MSR_OFFSET (CONFIG_16550_REGINCR*UART_MSR_INCR)
|
||||
#define UART_SCR_OFFSET (CONFIG_16550_REGINCR*UART_SCR_INCR)
|
||||
#define UART_USR_OFFSET (CONFIG_16550_REGINCR*UART_USR_INCR)
|
||||
#define UART_RBR_OFFSET 0 /* (DLAB =0) Receiver Buffer Register */
|
||||
#define UART_THR_OFFSET 0 /* (DLAB =0) Transmit Holding Register */
|
||||
#define UART_DLL_OFFSET 0 /* (DLAB =1) Divisor Latch LSB */
|
||||
#define UART_DLM_OFFSET 1 /* (DLAB =1) Divisor Latch MSB */
|
||||
#define UART_IER_OFFSET 1 /* (DLAB =0) Interrupt Enable Register */
|
||||
#define UART_IIR_OFFSET 2 /* Interrupt ID Register */
|
||||
#define UART_FCR_OFFSET 2 /* FIFO Control Register */
|
||||
#define UART_LCR_OFFSET 3 /* Line Control Register */
|
||||
#define UART_MCR_OFFSET 4 /* Modem Control Register */
|
||||
#define UART_LSR_OFFSET 5 /* Line Status Register */
|
||||
#define UART_MSR_OFFSET 6 /* Modem Status Register */
|
||||
#define UART_SCR_OFFSET 7 /* Scratch Pad Register */
|
||||
#define UART_USR_OFFSET 31 /* UART Status Register */
|
||||
#define UART_DLF_OFFSET 48 /* Divisor Latch Fraction Register */
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
@ -333,6 +319,64 @@ typedef uint64_t uart_addrwidth_t;
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
/* UART 16550 ops */
|
||||
|
||||
struct u16550_s;
|
||||
struct u16550_ops_s
|
||||
{
|
||||
CODE int (*isr)(int irq, FAR void *context, FAR void *arg);
|
||||
CODE uart_datawidth_t (*getreg)(FAR struct u16550_s *priv,
|
||||
unsigned int offset);
|
||||
CODE void (*putreg)(FAR struct u16550_s *priv,
|
||||
unsigned int offset,
|
||||
uart_datawidth_t value);
|
||||
CODE int (*ioctl)(FAR struct u16550_s *priv, int cmd, unsigned long arg);
|
||||
CODE FAR struct dma_chan_s *(*dmachan)(FAR struct u16550_s *priv,
|
||||
unsigned int ident);
|
||||
};
|
||||
|
||||
/* UART 16550 private data */
|
||||
|
||||
struct u16550_s
|
||||
{
|
||||
/* UART 16550 operations */
|
||||
|
||||
FAR const struct u16550_ops_s *ops;
|
||||
|
||||
uart_addrwidth_t uartbase; /* Base address of UART registers */
|
||||
uint8_t regincr;
|
||||
#ifdef HAVE_16550_UART_DMA
|
||||
int32_t dmatx;
|
||||
FAR struct dma_chan_s *chantx;
|
||||
int32_t dmarx;
|
||||
FAR struct dma_chan_s *chanrx;
|
||||
FAR char *dmarxbuf;
|
||||
size_t dmarxsize;
|
||||
volatile size_t dmarxhead;
|
||||
volatile size_t dmarxtail;
|
||||
int32_t dmarxtimeout;
|
||||
#endif
|
||||
#if !defined(CONFIG_16550_SUPRESS_CONFIG) || defined(HAVE_16550_UART_DMA)
|
||||
uint32_t baud; /* Configured baud */
|
||||
uint32_t uartclk; /* UART clock frequency */
|
||||
#endif
|
||||
#ifdef CONFIG_CLK
|
||||
FAR const char *clk_name; /* UART clock name */
|
||||
FAR struct clk_s *mclk; /* UART clock descriptor */
|
||||
#endif
|
||||
uart_datawidth_t ier; /* Saved IER value */
|
||||
int irq; /* IRQ associated with this UART */
|
||||
#ifndef CONFIG_16550_SUPRESS_CONFIG
|
||||
uint8_t parity; /* 0=none, 1=odd, 2=even */
|
||||
uint8_t bits; /* Number of bits (7 or 8) */
|
||||
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
|
||||
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
|
||||
bool flow; /* flow control (RTS/CTS) enabled */
|
||||
#endif
|
||||
#endif
|
||||
uart_datawidth_t rxtrigger; /* RX trigger level */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions Definitions
|
||||
****************************************************************************/
|
||||
@ -363,6 +407,36 @@ void u16550_earlyserialinit(void);
|
||||
|
||||
void u16550_serialinit(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_bind
|
||||
*
|
||||
* Description:
|
||||
* Bind 16550 compatible device with this driver.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int u16550_bind(FAR uart_dev_t *dev);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_interrupt
|
||||
*
|
||||
* Description:
|
||||
* Handle UART 16550 interrupt.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int u16550_interrupt(int irq, FAR void *context, FAR void *arg);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: u16550_putc
|
||||
*
|
||||
* Description:
|
||||
* Write one character to the UART (polled)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void u16550_putc(FAR struct u16550_s *priv, int ch);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: uart_getreg(), uart_putreg(), uart_ioctl()
|
||||
*
|
||||
@ -374,17 +448,16 @@ void u16550_serialinit(void);
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_SERIAL_UART_ARCH_MMIO
|
||||
uart_datawidth_t uart_getreg(uart_addrwidth_t base, unsigned int offset);
|
||||
void uart_putreg(uart_addrwidth_t base,
|
||||
uart_datawidth_t uart_getreg(FAR struct u16550_s *priv, unsigned int offset);
|
||||
void uart_putreg(FAR struct u16550_s *priv,
|
||||
unsigned int offset,
|
||||
uart_datawidth_t value);
|
||||
#endif
|
||||
|
||||
struct file; /* Forward reference */
|
||||
int uart_ioctl(struct file *filep, int cmd, unsigned long arg);
|
||||
int uart_ioctl(FAR struct u16550_s *priv, int cmd, unsigned long arg);
|
||||
|
||||
struct dma_chan_s;
|
||||
FAR struct dma_chan_s *uart_dmachan(uart_addrwidth_t base,
|
||||
FAR struct dma_chan_s *uart_dmachan(FAR struct u16550_s *priv,
|
||||
unsigned int ident);
|
||||
|
||||
#endif /* CONFIG_16550_UART */
|
||||
|
Loading…
Reference in New Issue
Block a user