mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-01 08:04:22 +08:00
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_ISR 0x14 /* Interrupt Status */
|
||||
#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_MODEMCR 0x24 /* Modem Control */
|
||||
#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_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */
|
||||
#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */
|
||||
#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */
|
||||
|
||||
/* Control Register Bit Definitions */
|
||||
#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_RXRST 0x00000001 /* RX logic reset */
|
||||
#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:
|
||||
@ -131,8 +135,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
CDNS_UART_IXR_TOUT)
|
||||
|
||||
/* 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:
|
||||
* The read/write Modem Control register controls the interface with the modem
|
||||
@ -172,18 +177,29 @@ struct cdns_uart {
|
||||
struct clk *pclk;
|
||||
unsigned int baud;
|
||||
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, \
|
||||
clk_rate_change_nb);
|
||||
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) {
|
||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_RXEMPTY)) {
|
||||
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->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)))
|
||||
return;
|
||||
@ -208,6 +226,9 @@ static void cdns_uart_handle_rx(struct uart_port *port, unsigned int isrstatus)
|
||||
u32 data;
|
||||
char status = TTY_NORMAL;
|
||||
|
||||
if (is_rxbs_support)
|
||||
rxbs_status = readl(port->membase + CDNS_UART_RXBS);
|
||||
|
||||
data = readl(port->membase + CDNS_UART_FIFO);
|
||||
|
||||
/* 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))
|
||||
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))
|
||||
continue;
|
||||
|
||||
port->icount.rx++;
|
||||
|
||||
if (isrstatus & CDNS_UART_IXR_PARITY) {
|
||||
port->icount.parity++;
|
||||
status = TTY_PARITY;
|
||||
} else if (isrstatus & CDNS_UART_IXR_FRAMING) {
|
||||
port->icount.frame++;
|
||||
status = TTY_FRAME;
|
||||
} else if (isrstatus & CDNS_UART_IXR_OVERRUN) {
|
||||
port->icount.overrun++;
|
||||
if (is_rxbs_support) {
|
||||
if ((rxbs_status & CDNS_UART_RXBS_PARITY)
|
||||
&& (status_mask & CDNS_UART_IXR_PARITY)) {
|
||||
port->icount.parity++;
|
||||
status = TTY_PARITY;
|
||||
}
|
||||
if ((rxbs_status & CDNS_UART_RXBS_FRAMING)
|
||||
&& (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,
|
||||
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)
|
||||
{
|
||||
struct cdns_uart *cdns_uart = port->private_data;
|
||||
bool is_brk_support;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
unsigned int status = 0;
|
||||
|
||||
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
}
|
||||
@ -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,
|
||||
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
|
||||
* @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 resource *res;
|
||||
struct cdns_uart *cdns_uart_data;
|
||||
const struct of_device_id *match;
|
||||
|
||||
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
|
||||
GFP_KERNEL);
|
||||
if (!cdns_uart_data)
|
||||
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");
|
||||
if (IS_ERR(cdns_uart_data->pclk)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 = {
|
||||
.probe = cdns_uart_probe,
|
||||
.remove = cdns_uart_remove,
|
||||
|
Loading…
Reference in New Issue
Block a user