xtensa/esp32: Fixes support for HW flow control

This commit is contained in:
Sara Souza
2021-06-02 09:55:50 -05:00
committed by Xiang Xiao
parent ed6b257fa4
commit 7dd131b4c1
2 changed files with 210 additions and 41 deletions
+6 -10
View File
@@ -521,18 +521,18 @@ config ESP32_UART0_RXPIN
default 3
range 0 39
if SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
config ESP32_UART0_RTSPIN
int "UART0 RTS Pin"
depends on SERIAL_IFLOWCONTROL
default 22
range 0 39
config ESP32_UART0_CTSPIN
int "UART0 CTS Pin"
depends on SERIAL_OFLOWCONTROL
default 19
range 0 39
endif # SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
endif # ESP32_UART0
if ESP32_UART1
@@ -547,20 +547,18 @@ config ESP32_UART1_RXPIN
default 9
range 0 39
if SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
config ESP32_UART1_RTSPIN
int "UART1 RTS Pin"
depends on SERIAL_IFLOWCONTROL
default 11
range 0 39
config ESP32_UART1_CTSPIN
int "UART1 CTS Pin"
depends on SERIAL_OFLOWCONTROL
default 6
range 0 39
endif # SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
endif # ESP32_UART1
if ESP32_UART2
@@ -575,20 +573,18 @@ config ESP32_UART2_RXPIN
default 16
range 0 39
if SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
config ESP32_UART2_RTSPIN
int "UART2 RTS Pin"
depends on SERIAL_IFLOWCONTROL
default 7
range 0 39
config ESP32_UART2_CTSPIN
int "UART2 CTS Pin"
depends on SERIAL_OFLOWCONTROL
default 8
range 0 39
endif # SERIAL_IFLOWCONTROL || SERIAL_OFLOWCONTROL
endif # ESP32_UART2
endmenu # UART configuration
+204 -31
View File
@@ -137,10 +137,12 @@ struct esp32_config_s
uint8_t rxpin; /* Rx pin number (0-39) */
uint8_t txsig; /* Tx signal */
uint8_t rxsig; /* Rx signal */
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
#ifdef CONFIG_SERIAL_IFLOWCONTROL
uint8_t rtspin; /* RTS pin number (0-39) */
uint8_t ctspin; /* CTS pin number (0-39) */
uint8_t rtssig; /* RTS signal */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
uint8_t ctspin; /* CTS pin number (0-39) */
uint8_t ctssig; /* CTS signal */
#endif
};
@@ -156,8 +158,11 @@ struct esp32_dev_s
uint8_t parity; /* 0=none, 1=odd, 2=even */
uint8_t bits; /* Number of bits (5-9) */
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
bool flowc; /* Input flow control (RTS) enabled */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
bool iflow; /* Input flow control (RTS) enabled */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
bool oflow; /* Output flow control (CTS) enabled */
#endif
};
@@ -178,6 +183,10 @@ static void esp32_send(struct uart_dev_s *dev, int ch);
static void esp32_txint(struct uart_dev_s *dev, bool enable);
static bool esp32_txready(struct uart_dev_s *dev);
static bool esp32_txempty(struct uart_dev_s *dev);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool esp32_rxflowcontrol(struct uart_dev_s *dev,
unsigned int nbuffered, bool upper);
#endif
/****************************************************************************
* Private Data
@@ -186,6 +195,7 @@ static bool esp32_txempty(struct uart_dev_s *dev);
#define UART_TX_FIFO_SIZE 128
#define UART_RX_FIFO_FULL_THRHD 112
#define UART_RX_TOUT_THRHD_VALUE 0x02
#define UART_RX_FLOW_THRHD_VALUE 64 /* Almost half RX FIFO size */
static const struct uart_ops_s g_uart_ops =
{
@@ -197,13 +207,13 @@ static const struct uart_ops_s g_uart_ops =
.receive = esp32_receive,
.rxint = esp32_rxint,
.rxavailable = esp32_rxavailable,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rxflowcontrol = NULL,
#endif
.send = esp32_send,
.txint = esp32_txint,
.txready = esp32_txready,
.txempty = esp32_txempty,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rxflowcontrol = esp32_rxflowcontrol,
#endif
};
/* I/O buffers */
@@ -233,10 +243,12 @@ static const struct esp32_config_s g_uart0config =
.rxpin = CONFIG_ESP32_UART0_RXPIN,
.txsig = U0TXD_OUT_IDX,
.rxsig = U0RXD_IN_IDX,
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rtspin = CONFIG_ESP32_UART0_RTSPIN,
.ctspin = CONFIG_ESP32_UART0_CTSPIN,
.rtssig = U0RTS_OUT_IDX,
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
.ctspin = CONFIG_ESP32_UART0_CTSPIN,
.ctssig = U0CTS_IN_IDX,
#endif
};
@@ -248,6 +260,20 @@ static struct esp32_dev_s g_uart0priv =
.parity = CONFIG_UART0_PARITY,
.bits = CONFIG_UART0_BITS,
.stopbits2 = CONFIG_UART0_2STOP,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#ifdef CONFIG_UART0_IFLOWCONTROL
.iflow = true, /* Input flow control (RTS) enabled */
#else
.iflow = false, /* Input flow control (RTS) disabled */
#endif
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
#ifdef CONFIG_UART0_OFLOWCONTROL
.oflow = true, /* Output flow control (CTS) enabled */
#else
.oflow = false, /* Output flow control (CTS) disabled */
#endif
#endif
};
static uart_dev_t g_uart0port =
@@ -279,10 +305,12 @@ static const struct esp32_config_s g_uart1config =
.rxpin = CONFIG_ESP32_UART1_RXPIN,
.txsig = U1TXD_OUT_IDX,
.rxsig = U1RXD_IN_IDX,
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rtspin = CONFIG_ESP32_UART1_RTSPIN,
.ctspin = CONFIG_ESP32_UART1_CTSPIN,
.rtssig = U1RTS_OUT_IDX,
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
.ctspin = CONFIG_ESP32_UART1_CTSPIN,
.ctssig = U1CTS_IN_IDX,
#endif
};
@@ -294,6 +322,20 @@ static struct esp32_dev_s g_uart1priv =
.parity = CONFIG_UART1_PARITY,
.bits = CONFIG_UART1_BITS,
.stopbits2 = CONFIG_UART1_2STOP,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#ifdef CONFIG_UART1_IFLOWCONTROL
.iflow = true, /* input flow control (RTS) enabled */
#else
.iflow = false, /* input flow control (RTS) disabled */
#endif
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
#ifdef CONFIG_UART1_OFLOWCONTROL
.oflow = true, /* output flow control (CTS) enabled */
#else
.oflow = false, /* output flow control (CTS) disabled */
#endif
#endif
};
static uart_dev_t g_uart1port =
@@ -325,10 +367,12 @@ static const struct esp32_config_s g_uart2config =
.rxpin = CONFIG_ESP32_UART2_RXPIN,
.txsig = U2TXD_OUT_IDX,
.rxsig = U2RXD_IN_IDX,
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
#ifdef CONFIG_SERIAL_IFLOWCONTROL
.rtspin = CONFIG_ESP32_UART2_RTSPIN,
.ctspin = CONFIG_ESP32_UART2_CTSPIN,
.rtssig = U2RTS_OUT_IDX,
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
.ctspin = CONFIG_ESP32_UART2_CTSPIN,
.ctssig = U2CTS_IN_IDX,
#endif
};
@@ -340,6 +384,20 @@ static struct esp32_dev_s g_uart2priv =
.parity = CONFIG_UART2_PARITY,
.bits = CONFIG_UART2_BITS,
.stopbits2 = CONFIG_UART2_2STOP,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
#ifdef CONFIG_UART2_IFLOWCONTROL
.iflow = true, /* input flow control (RTS) enabled */
#else
.iflow = false, /* input flow control (RTS) disabled */
#endif
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
#ifdef CONFIG_UART2_OFLOWCONTROL
.oflow = true, /* output flow control (CTS) enabled */
#else
.oflow = false, /* output flow control (CTS) disabled */
#endif
#endif
};
static uart_dev_t g_uart2port =
@@ -532,15 +590,16 @@ static int esp32_setup(struct uart_dev_s *dev)
conf0 = UART_TICK_REF_ALWAYS_ON;
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
/* Check if flow control is enabled */
#ifdef CONFIG_SERIAL_OFLOWCONTROL
/* Check if output flow control is enabled for this UART controller. */
if (priv->flowc)
if (priv->oflow)
{
/* Enable hardware flow control */
/* Enable output hardware flow control */
conf0 |= UART_TX_FLOW_EN;
}
#endif
/* OR in settings for the selected number of bits */
@@ -612,8 +671,21 @@ static int esp32_setup(struct uart_dev_s *dev)
VALUE_TO_FIELD(UART_RX_TOUT_THRHD_VALUE, UART_RX_TOUT_THRHD) |
UART_RX_TOUT_EN;
putreg32(regval, UART_CONF1_REG(priv->config->id));
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL
/* Check if input flow control is enabled for this UART controller */
if (priv->iflow)
{
/* Enable input hardware flow control */
regval |= VALUE_TO_FIELD(UART_RX_FLOW_THRHD_VALUE, UART_RX_FLOW_THRHD)
| UART_RX_FLOW_EN;
modifyreg32(UART_CONF1_REG(priv->config->id), 0, regval);
}
#endif
#endif
return OK;
}
@@ -895,8 +967,11 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
/* Return flow control */
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
termiosp->c_cflag |= (priv->flowc) ? (CCTS_OFLOW | CRTS_IFLOW): 0;
#ifdef CONFIG_SERIAL_OFLOWCONTROL
termiosp->c_cflag |= (priv->oflow) ? CCTS_OFLOW : 0;
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL
termiosp->c_cflag |= (priv->iflow) ? CRTS_IFLOW : 0;
#endif
/* Return baud */
@@ -939,8 +1014,11 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
uint8_t parity;
uint8_t nbits;
bool stop2;
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
bool flowc;
#ifdef CONFIG_SERIAL_IFLOWCONTROL
bool iflow;
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
bool oflow;
#endif
if (!termiosp)
@@ -1000,8 +1078,11 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
/* Decode flow control */
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
flowc = (termiosp->c_cflag & (CCTS_OFLOW | CRTS_IFLOW)) != 0;
#ifdef CONFIG_SERIAL_IFLOWCONTROL
iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0;
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0;
#endif
/* Verify that all settings are valid before committing */
@@ -1013,8 +1094,11 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
priv->parity = parity;
priv->bits = nbits;
priv->stopbits2 = stop2;
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
priv->flowc = flowc;
#ifdef CONFIG_SERIAL_IFLOWCONTROL
priv->iflow = iflow;
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
priv->oflow = oflow;
#endif
/* effect the changes immediately - note that we do not
* implement TCSADRAIN / TCSAFLUSH
@@ -1240,15 +1324,104 @@ static void esp32_config_pins(struct esp32_dev_s *priv)
esp32_configgpio(priv->config->rxpin, INPUT_FUNCTION_3);
esp32_gpio_matrix_in(priv->config->rxpin, priv->config->rxsig, 0);
#if defined(CONFIG_SERIAL_IFLOWCONTROL) || defined(CONFIG_SERIAL_OFLOWCONTROL)
esp32_configgpio(priv->config->rtspin, OUTPUT_FUNCTION_3);
esp32_gpio_matrix_out(priv->config->rtspin, priv->config->rtssig, 0, 0);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
if (priv->iflow)
{
esp32_configgpio(priv->config->rtspin, OUTPUT_FUNCTION_3);
esp32_gpio_matrix_out(priv->config->rtspin, priv->config->rtssig,
0, 0);
}
esp32_configgpio(priv->config->ctspin, INPUT_FUNCTION_3);
esp32_gpio_matrix_in(priv->config->ctspin, priv->config->ctssig, 0);
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
if (priv->oflow)
{
esp32_configgpio(priv->config->ctspin, INPUT_FUNCTION_3);
esp32_gpio_matrix_in(priv->config->ctspin, priv->config->ctssig, 0);
}
#endif
}
/****************************************************************************
* Name: esp32_rxflowcontrol
*
* Description:
* Called when upper half RX buffer is full (or exceeds configured
* watermark levels if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
* Return true if UART activated RX flow control to block more incoming
* data.
* NOTE: ESP32 has a hardware RX FIFO threshold mechanism to control RTS
* line and to stop receiving data. This is very similar to the concept
* behind upper watermark level. The hardware threshold is used here
* to control the RTS line. When setting the threshold to zero, RTS will
* imediately be asserted. If nbuffered = 0 or the lower watermark is
* crossed and the serial driver decides to disable RX flow control, the
* threshold will be changed to UART_RX_FLOW_THRHD_VALUE, which is almost
* half the HW RX FIFO capacity. It keeps some space to keep the data
* received after the RTS is asserted, but before the sender stops.
*
* Input Parameters:
* dev - UART device instance
* nbuffered - the number of characters currently buffered
* (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is
* not defined the value will be 0 for an empty buffer or the
* defined buffer size for a full buffer)
* upper - true indicates the upper watermark was crossed where
* false indicates the lower watermark has been crossed
*
* Returned Value:
* true if RX flow control activated.
*
****************************************************************************/
#ifdef CONFIG_SERIAL_IFLOWCONTROL
static bool esp32_rxflowcontrol(struct uart_dev_s *dev,
unsigned int nbuffered, bool upper)
{
bool ret = false;
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
if (priv->iflow)
{
if (nbuffered == 0 || upper == false)
{
uint32_t regval;
/* Empty buffer, RTS should be de-asserted and logic in above
* layers should re-enable RX interrupt.
*/
regval = VALUE_TO_FIELD(UART_RX_FLOW_THRHD_VALUE,
UART_RX_FLOW_THRHD);
modifyreg32(UART_CONF1_REG(priv->config->id), 0, regval);
esp32_rxint(dev, true);
ret = false;
}
else
{
/* If the RX buffer is not zero and watermarks are not enabled,
* then this function is called to announce RX buffer is full.
* The first thing it should do is to imediately assert RTS.
*/
modifyreg32(UART_CONF1_REG(priv->config->id), UART_RX_FLOW_THRHD_M,
0);
/* Software RX FIFO is full, so besides asserting RTS, it's
* necessary to disable RX interrupts to prevent remaining bytes
* (that arrive after asserting RTS) to be pushed to the
* SW RX FIFO.
*/
esp32_rxint(dev, false);
ret = true;
}
}
return ret;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/