mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-28 21:33:52 +00:00
8250: microchip: pci1xxxx: Add Burst mode reception support in uart driver for writing into FIFO
In PCI1XXXX C0 endpoint, support for Burst mode is added. pci1xxxx_handle_irq checks the burst status and based on that incoming characters are received in DWORDs, RX handling is done in pci1xxxx_rx_burst. While reading the burst status the RX error is checked and the corresponding error statistics are updated. Signed-off-by: Rengarajan S <rengarajan.s@microchip.com> Link: https://lore.kernel.org/r/20231215151123.41812-4-rengarajan.s@microchip.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b7fbca372b
commit
aba8290f36
1 changed files with 121 additions and 2 deletions
|
@ -66,6 +66,9 @@
|
|||
#define SYSLOCK_SLEEP_TIMEOUT 100
|
||||
#define SYSLOCK_RETRY_CNT 1000
|
||||
|
||||
#define UART_RX_BYTE_FIFO 0x00
|
||||
#define UART_FIFO_CTL 0x02
|
||||
|
||||
#define UART_ACTV_REG 0x11
|
||||
#define UART_BLOCK_SET_ACTIVE BIT(0)
|
||||
|
||||
|
@ -96,8 +99,23 @@
|
|||
#define UART_RESET_REG 0x94
|
||||
#define UART_RESET_D3_RESET_DISABLE BIT(16)
|
||||
|
||||
#define UART_BURST_STATUS_REG 0x9C
|
||||
#define UART_RX_BURST_FIFO 0xA4
|
||||
|
||||
#define MAX_PORTS 4
|
||||
#define PORT_OFFSET 0x100
|
||||
#define RX_BUF_SIZE 512
|
||||
#define UART_BYTE_SIZE 1
|
||||
#define UART_BURST_SIZE 4
|
||||
|
||||
#define UART_BST_STAT_RX_COUNT_MASK 0x00FF
|
||||
#define UART_BST_STAT_IIR_INT_PEND 0x100000
|
||||
#define UART_LSR_OVERRUN_ERR_CLR 0x43
|
||||
#define UART_BST_STAT_LSR_RX_MASK 0x9F000000
|
||||
#define UART_BST_STAT_LSR_RX_ERR_MASK 0x9E000000
|
||||
#define UART_BST_STAT_LSR_OVERRUN_ERR 0x2000000
|
||||
#define UART_BST_STAT_LSR_PARITY_ERR 0x4000000
|
||||
#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
|
||||
|
||||
struct pci1xxxx_8250 {
|
||||
unsigned int nr;
|
||||
|
@ -249,6 +267,103 @@ static int pci1xxxx_rs485_config(struct uart_port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u32 pci1xxxx_read_burst_status(struct uart_port *port)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
status = readl(port->membase + UART_BURST_STATUS_REG);
|
||||
if (status & UART_BST_STAT_LSR_RX_ERR_MASK) {
|
||||
if (status & UART_BST_STAT_LSR_OVERRUN_ERR) {
|
||||
writeb(UART_LSR_OVERRUN_ERR_CLR,
|
||||
port->membase + UART_FIFO_CTL);
|
||||
port->icount.overrun++;
|
||||
}
|
||||
|
||||
if (status & UART_BST_STAT_LSR_FRAME_ERR)
|
||||
port->icount.frame++;
|
||||
|
||||
if (status & UART_BST_STAT_LSR_PARITY_ERR)
|
||||
port->icount.parity++;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void pci1xxxx_process_read_data(struct uart_port *port,
|
||||
unsigned char *rx_buff, u32 *buff_index,
|
||||
u32 *valid_byte_count)
|
||||
{
|
||||
u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
|
||||
u32 *burst_buf;
|
||||
|
||||
/*
|
||||
* Depending on the RX Trigger Level the number of bytes that can be
|
||||
* stored in RX FIFO at a time varies. Each transaction reads data
|
||||
* in DWORDs. If there are less than four remaining valid_byte_count
|
||||
* to read, the data is received one byte at a time.
|
||||
*/
|
||||
while (valid_burst_count--) {
|
||||
if (*buff_index > (RX_BUF_SIZE - UART_BURST_SIZE))
|
||||
break;
|
||||
burst_buf = (u32 *)&rx_buff[*buff_index];
|
||||
*burst_buf = readl(port->membase + UART_RX_BURST_FIFO);
|
||||
*buff_index += UART_BURST_SIZE;
|
||||
*valid_byte_count -= UART_BURST_SIZE;
|
||||
}
|
||||
|
||||
while (*valid_byte_count) {
|
||||
if (*buff_index > RX_BUF_SIZE)
|
||||
break;
|
||||
rx_buff[*buff_index] = readb(port->membase +
|
||||
UART_RX_BYTE_FIFO);
|
||||
*buff_index += UART_BYTE_SIZE;
|
||||
*valid_byte_count -= UART_BYTE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
|
||||
{
|
||||
u32 valid_byte_count = uart_status & UART_BST_STAT_RX_COUNT_MASK;
|
||||
struct tty_port *tty_port = &port->state->port;
|
||||
unsigned char rx_buff[RX_BUF_SIZE];
|
||||
u32 buff_index = 0;
|
||||
u32 copied_len;
|
||||
|
||||
if (valid_byte_count != 0 &&
|
||||
valid_byte_count < RX_BUF_SIZE) {
|
||||
pci1xxxx_process_read_data(port, rx_buff, &buff_index,
|
||||
&valid_byte_count);
|
||||
|
||||
copied_len = (u32)tty_insert_flip_string(tty_port, rx_buff,
|
||||
buff_index);
|
||||
|
||||
if (copied_len != buff_index)
|
||||
port->icount.overrun += buff_index - copied_len;
|
||||
|
||||
port->icount.rx += buff_index;
|
||||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
}
|
||||
|
||||
static int pci1xxxx_handle_irq(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 status;
|
||||
|
||||
status = pci1xxxx_read_burst_status(port);
|
||||
|
||||
if (status & UART_BST_STAT_IIR_INT_PEND)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
if (status & UART_BST_STAT_LSR_RX_MASK)
|
||||
pci1xxxx_rx_burst(port, status);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool pci1xxxx_port_suspend(int line)
|
||||
{
|
||||
struct uart_8250_port *up = serial8250_get_port(line);
|
||||
|
@ -360,7 +475,7 @@ static int pci1xxxx_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static int pci1xxxx_setup(struct pci_dev *pdev,
|
||||
struct uart_8250_port *port, int port_idx)
|
||||
struct uart_8250_port *port, int port_idx, int rev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -372,6 +487,10 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
|
|||
port->port.rs485_config = pci1xxxx_rs485_config;
|
||||
port->port.rs485_supported = pci1xxxx_rs485_supported;
|
||||
|
||||
/* From C0 rev Burst operation is supported */
|
||||
if (rev >= 0xC0)
|
||||
port->port.handle_irq = pci1xxxx_handle_irq;
|
||||
|
||||
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -491,7 +610,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
|
|||
else
|
||||
uart.port.irq = pci_irq_vector(pdev, 0);
|
||||
|
||||
rc = pci1xxxx_setup(pdev, &uart, port_idx);
|
||||
rc = pci1xxxx_setup(pdev, &uart, port_idx, priv->dev_rev);
|
||||
if (rc) {
|
||||
dev_warn(dev, "Failed to setup port %u\n", i);
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue