serial: xuartps: Adds RXBS register support for zynqmp
This patch adds RXBS register access support for zynqmp. To avoid the corner error conditions it will consider only RXBS[2:0] bits while checking the error conditions (Parity,Framing and BRAK). Signed-off-by: Nava kishore Manne <navam@xilinx.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
54f19b4a67
commit
3816b2f886
@ -57,7 +57,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||||||
#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
|
#define CDNS_UART_IMR 0x10 /* Interrupt Mask */
|
||||||
#define CDNS_UART_ISR 0x14 /* Interrupt Status */
|
#define CDNS_UART_ISR 0x14 /* Interrupt Status */
|
||||||
#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
|
#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */
|
||||||
#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
|
#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */
|
||||||
#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
|
#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */
|
||||||
#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
|
#define CDNS_UART_MODEMCR 0x24 /* Modem Control */
|
||||||
#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
|
#define CDNS_UART_MODEMSR 0x28 /* Modem Status */
|
||||||
@ -68,6 +68,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||||||
#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
|
#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */
|
||||||
#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
|
#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
|
||||||
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
|
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
|
||||||
|
#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
|
||||||
|
|
||||||
/* Control Register Bit Definitions */
|
/* Control Register Bit Definitions */
|
||||||
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
|
#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */
|
||||||
@ -79,6 +80,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||||||
#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
|
#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */
|
||||||
#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
|
#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */
|
||||||
#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
|
#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */
|
||||||
|
#define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */
|
||||||
|
#define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */
|
||||||
|
#define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mode Register:
|
* Mode Register:
|
||||||
@ -131,8 +135,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
|||||||
CDNS_UART_IXR_TOUT)
|
CDNS_UART_IXR_TOUT)
|
||||||
|
|
||||||
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
|
/* Goes in read_status_mask for break detection as the HW doesn't do it*/
|
||||||
#define CDNS_UART_IXR_BRK 0x80000000
|
#define CDNS_UART_IXR_BRK 0x00002000
|
||||||
|
|
||||||
|
#define CDNS_UART_RXBS_SUPPORT BIT(1)
|
||||||
/*
|
/*
|
||||||
* Modem Control register:
|
* Modem Control register:
|
||||||
* The read/write Modem Control register controls the interface with the modem
|
* The read/write Modem Control register controls the interface with the modem
|
||||||
@ -172,18 +177,29 @@ struct cdns_uart {
|
|||||||
struct clk *pclk;
|
struct clk *pclk;
|
||||||
unsigned int baud;
|
unsigned int baud;
|
||||||
struct notifier_block clk_rate_change_nb;
|
struct notifier_block clk_rate_change_nb;
|
||||||
|
u32 quirks;
|
||||||
|
};
|
||||||
|
struct cdns_platform_data {
|
||||||
|
u32 quirks;
|
||||||
};
|
};
|
||||||
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
|
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
|
||||||
clk_rate_change_nb);
|
clk_rate_change_nb);
|
||||||
|
|
||||||
static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
||||||
{
|
{
|
||||||
|
struct cdns_uart *cdns_uart = port->private_data;
|
||||||
|
bool is_rxbs_support;
|
||||||
|
unsigned int rxbs_status = 0;
|
||||||
|
unsigned int status_mask;
|
||||||
|
|
||||||
|
is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* There is no hardware break detection, so we interpret framing
|
* There is no hardware break detection, so we interpret framing
|
||||||
* error with all-zeros data as a break sequence. Most of the time,
|
* error with all-zeros data as a break sequence. Most of the time,
|
||||||
* there's another non-zero byte at the end of the sequence.
|
* there's another non-zero byte at the end of the sequence.
|
||||||
*/
|
*/
|
||||||
if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) {
|
||||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||||
CDNS_UART_SR_RXEMPTY)) {
|
CDNS_UART_SR_RXEMPTY)) {
|
||||||
if (!readl(port->membase + CDNS_UART_FIFO)) {
|
if (!readl(port->membase + CDNS_UART_FIFO)) {
|
||||||
@ -200,6 +216,8 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
|||||||
|
|
||||||
isrstatus &= port->read_status_mask;
|
isrstatus &= port->read_status_mask;
|
||||||
isrstatus &= ~port->ignore_status_mask;
|
isrstatus &= ~port->ignore_status_mask;
|
||||||
|
status_mask = port->read_status_mask;
|
||||||
|
status_mask &= ~port->ignore_status_mask;
|
||||||
|
|
||||||
if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
|
if (!(isrstatus & (CDNS_UART_IXR_TOUT | CDNS_UART_IXR_RXTRIG)))
|
||||||
return;
|
return;
|
||||||
@ -208,6 +226,9 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
|||||||
u32 data;
|
u32 data;
|
||||||
char status = TTY_NORMAL;
|
char status = TTY_NORMAL;
|
||||||
|
|
||||||
|
if (is_rxbs_support)
|
||||||
|
rxbs_status = readl(port->membase + CDNS_UART_RXBS);
|
||||||
|
|
||||||
data = readl(port->membase + CDNS_UART_FIFO);
|
data = readl(port->membase + CDNS_UART_FIFO);
|
||||||
|
|
||||||
/* Non-NULL byte after BREAK is garbage (99%) */
|
/* Non-NULL byte after BREAK is garbage (99%) */
|
||||||
@ -217,21 +238,41 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
|||||||
if (uart_handle_break(port))
|
if (uart_handle_break(port))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) {
|
||||||
|
port->icount.brk++;
|
||||||
|
status = TTY_BREAK;
|
||||||
|
if (uart_handle_break(port))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (uart_handle_sysrq_char(port, data))
|
if (uart_handle_sysrq_char(port, data))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
port->icount.rx++;
|
port->icount.rx++;
|
||||||
|
|
||||||
if (isrstatus & CDNS_UART_IXR_PARITY) {
|
if (is_rxbs_support) {
|
||||||
port->icount.parity++;
|
if ((rxbs_status & CDNS_UART_RXBS_PARITY)
|
||||||
status = TTY_PARITY;
|
&& (status_mask & CDNS_UART_IXR_PARITY)) {
|
||||||
} else if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
port->icount.parity++;
|
||||||
port->icount.frame++;
|
status = TTY_PARITY;
|
||||||
status = TTY_FRAME;
|
}
|
||||||
} else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
|
if ((rxbs_status & CDNS_UART_RXBS_FRAMING)
|
||||||
port->icount.overrun++;
|
&& (status_mask & CDNS_UART_IXR_PARITY)) {
|
||||||
|
port->icount.frame++;
|
||||||
|
status = TTY_FRAME;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isrstatus & CDNS_UART_IXR_PARITY) {
|
||||||
|
port->icount.parity++;
|
||||||
|
status = TTY_PARITY;
|
||||||
|
}
|
||||||
|
if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||||
|
port->icount.frame++;
|
||||||
|
status = TTY_FRAME;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (isrstatus & CDNS_UART_IXR_OVERRUN)
|
||||||
|
port->icount.overrun++;
|
||||||
|
|
||||||
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
|
uart_insert_char(port, isrstatus, CDNS_UART_IXR_OVERRUN,
|
||||||
data, status);
|
data, status);
|
||||||
@ -736,10 +777,14 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
|||||||
*/
|
*/
|
||||||
static int cdns_uart_startup(struct uart_port *port)
|
static int cdns_uart_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
|
struct cdns_uart *cdns_uart = port->private_data;
|
||||||
|
bool is_brk_support;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int status = 0;
|
unsigned int status = 0;
|
||||||
|
|
||||||
|
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
|
||||||
|
|
||||||
spin_lock_irqsave(&port->lock, flags);
|
spin_lock_irqsave(&port->lock, flags);
|
||||||
|
|
||||||
/* Disable the TX and RX */
|
/* Disable the TX and RX */
|
||||||
@ -794,7 +839,11 @@ static int cdns_uart_startup(struct uart_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set the Interrupt Registers with desired interrupts */
|
/* Set the Interrupt Registers with desired interrupts */
|
||||||
writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
|
if (is_brk_support)
|
||||||
|
writel(CDNS_UART_RX_IRQS | CDNS_UART_IXR_BRK,
|
||||||
|
port->membase + CDNS_UART_IER);
|
||||||
|
else
|
||||||
|
writel(CDNS_UART_RX_IRQS, port->membase + CDNS_UART_IER);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1328,6 +1377,18 @@ static int cdns_uart_resume(struct device *device)
|
|||||||
static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
|
static SIMPLE_DEV_PM_OPS(cdns_uart_dev_pm_ops, cdns_uart_suspend,
|
||||||
cdns_uart_resume);
|
cdns_uart_resume);
|
||||||
|
|
||||||
|
static const struct cdns_platform_data zynqmp_uart_def = {
|
||||||
|
.quirks = CDNS_UART_RXBS_SUPPORT, };
|
||||||
|
|
||||||
|
/* Match table for of_platform binding */
|
||||||
|
static const struct of_device_id cdns_uart_of_match[] = {
|
||||||
|
{ .compatible = "xlnx,xuartps", },
|
||||||
|
{ .compatible = "cdns,uart-r1p8", },
|
||||||
|
{ .compatible = "cdns,uart-r1p12", .data = &zynqmp_uart_def },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cdns_uart_probe - Platform driver probe
|
* cdns_uart_probe - Platform driver probe
|
||||||
* @pdev: Pointer to the platform device structure
|
* @pdev: Pointer to the platform device structure
|
||||||
@ -1340,12 +1401,20 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||||||
struct uart_port *port;
|
struct uart_port *port;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct cdns_uart *cdns_uart_data;
|
struct cdns_uart *cdns_uart_data;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
|
||||||
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
|
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!cdns_uart_data)
|
if (!cdns_uart_data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
|
||||||
|
if (match && match->data) {
|
||||||
|
const struct cdns_platform_data *data = match->data;
|
||||||
|
|
||||||
|
cdns_uart_data->quirks = data->quirks;
|
||||||
|
}
|
||||||
|
|
||||||
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
|
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk");
|
||||||
if (IS_ERR(cdns_uart_data->pclk)) {
|
if (IS_ERR(cdns_uart_data->pclk)) {
|
||||||
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
|
cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk");
|
||||||
@ -1471,14 +1540,6 @@ static int cdns_uart_remove(struct platform_device *pdev)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match table for of_platform binding */
|
|
||||||
static const struct of_device_id cdns_uart_of_match[] = {
|
|
||||||
{ .compatible = "xlnx,xuartps", },
|
|
||||||
{ .compatible = "cdns,uart-r1p8", },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver cdns_uart_platform_driver = {
|
static struct platform_driver cdns_uart_platform_driver = {
|
||||||
.probe = cdns_uart_probe,
|
.probe = cdns_uart_probe,
|
||||||
.remove = cdns_uart_remove,
|
.remove = cdns_uart_remove,
|
||||||
|
Loading…
Reference in New Issue
Block a user