NVIDIA: SAUCE: serial: pl011: add eord interrupt support

BugLink: https://bugs.launchpad.net/bugs/2080908

Nvidia Tegra pl011 controller supports EORD interrupt that triggers
when there is no data in RX FIFO and no data is received for 4 frame
duration.

Add support for EORD interrupt.

http://nvbugs/3414248

Signed-off-by: kartik <kkartik@nvidia.com>
Reviewed-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Tested-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Acked-by: Noah Wager <noah.wager@canonical.com>
Acked-by: Jacob Martin <jacob.martin@canonical.com>
Signed-off-by: Noah Wager <noah.wager@canonical.com>
This commit is contained in:
kartik
2021-11-18 13:49:09 +05:30
committed by Noah Wager
parent 361e4d4dfd
commit d34b3dad7d
2 changed files with 111 additions and 20 deletions
+95 -20
View File
@@ -79,6 +79,10 @@ enum {
REG_ST_ITIP,
REG_ST_ABCR,
REG_ST_ABIMSC,
REG_NV_MIS,
REG_NV_MIM,
REG_NV_MMIS,
REG_NV_MIC,
/* The size of the array - must be last */
REG_ARRAY_SIZE,
@@ -117,6 +121,7 @@ struct vendor_data {
bool fixed_options;
bool enable_car;
bool dma_workaround;
bool eord_interrupt;
unsigned int (*get_fifosize)(struct amba_device *dev);
};
@@ -126,23 +131,6 @@ static unsigned int get_fifosize_arm(struct amba_device *dev)
return amba_rev(dev) < 3 ? 16 : 32;
}
static struct vendor_data vendor_nvidia = {
.reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
.fr_ri = UART011_FR_RI,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
.always_enabled = false,
.fixed_options = false,
.enable_car = true,
.dma_workaround = true,
.get_fifosize = get_fifosize_arm,
};
static struct vendor_data vendor_arm = {
.reg_offset = pl011_std_offsets,
.ifls = UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
@@ -189,6 +177,44 @@ static const struct vendor_data vendor_qdt_qdf2400_e44 = {
};
#endif
static u16 pl011_tegra_offsets[REG_ARRAY_SIZE] = {
[REG_DR] = UART01x_DR,
[REG_FR] = UART01x_FR,
[REG_LCRH_RX] = UART011_LCRH,
[REG_LCRH_TX] = UART011_LCRH,
[REG_IBRD] = UART011_IBRD,
[REG_FBRD] = UART011_FBRD,
[REG_CR] = UART011_CR,
[REG_IFLS] = UART011_IFLS,
[REG_IMSC] = UART011_IMSC,
[REG_RIS] = UART011_RIS,
[REG_MIS] = UART011_MIS,
[REG_ICR] = UART011_ICR,
[REG_DMACR] = UART011_DMACR,
[REG_NV_MIS] = NV_UART011_MIS,
[REG_NV_MIM] = NV_UART011_MIM,
[REG_NV_MMIS] = NV_UART011_MIS,
[REG_NV_MIC] = NV_UART011_MIC,
};
static struct vendor_data vendor_nvidia = {
.reg_offset = pl011_tegra_offsets,
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fr_busy = UART01x_FR_BUSY,
.fr_dsr = UART01x_FR_DSR,
.fr_cts = UART01x_FR_CTS,
.fr_ri = UART011_FR_RI,
.oversampling = false,
.dma_threshold = false,
.cts_event_workaround = false,
.always_enabled = false,
.fixed_options = false,
.enable_car = true,
.dma_workaround = true,
.eord_interrupt = true,
.get_fifosize = get_fifosize_arm,
};
static u16 pl011_st_offsets[REG_ARRAY_SIZE] = {
[REG_DR] = UART01x_DR,
[REG_ST_DMAWM] = ST_UART011_DMAWM,
@@ -1426,6 +1452,9 @@ static void pl011_stop_rx(struct uart_port *port)
UART011_PEIM | UART011_BEIM | UART011_OEIM);
pl011_write(uap->im, uap, REG_IMSC);
if (uap->vendor->eord_interrupt)
pl011_write(~NV_UART011_EORDIM, uap, REG_NV_MIM);
pl011_dma_rx_stop(uap);
}
@@ -1580,6 +1609,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
unsigned long flags;
int handled = 0;
uart_port_lock(&uap->port);
@@ -1596,6 +1626,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
pl011_dma_rx_irq(uap);
else
pl011_rx_chars(uap);
/*
* Clear EORD interrupt as receive timeout
* interrupt already triggered.
*/
if (uap->vendor->eord_interrupt)
pl011_write(NV_UART011_EORDIC, uap,
REG_NV_MIC);
}
if (status & (UART011_DSRMIS | UART011_DCDMIS |
UART011_CTSMIS | UART011_RIMIS))
@@ -1608,10 +1646,38 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
status = pl011_read(uap, REG_RIS) & uap->im;
} while (status != 0);
handled = 1;
} else {
/*
* We are here because Receive timeout interrupt did not fire.
* Check if EORD interrupt is supported.
*/
if (!uap->vendor->eord_interrupt)
goto out;
status = pl011_read(uap, REG_NV_MMIS);
if (!status)
goto out;
do {
pl011_write(NV_UART011_EORDIC, uap,
REG_NV_MIC);
if (status & NV_UART011_EORDIS) {
if (pl011_dma_rx_running(uap))
pl011_dma_rx_irq(uap);
else
pl011_rx_chars(uap);
}
status = pl011_read(uap, REG_NV_MMIS);
} while (status != 0);
handled = 1;
}
uart_unlock_and_check_sysrq(&uap->port);
out:
uart_port_unlock_irqrestore(&uap->port, flags);
return IRQ_RETVAL(handled);
}
@@ -1850,8 +1916,13 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
}
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
if (!pl011_dma_rx_running(uap)) {
uap->im |= UART011_RXIM;
} else {
/* Enable EORD interrupt only if DMA is running. */
if (uap->vendor->eord_interrupt)
pl011_write(NV_UART011_EORDIM, uap, REG_NV_MIM);
}
pl011_write(uap->im, uap, REG_IMSC);
uart_port_unlock_irqrestore(&uap->port, flags);
}
@@ -1864,8 +1935,12 @@ static void pl011_unthrottle_rx(struct uart_port *port)
uart_port_lock_irqsave(&uap->port, &flags);
uap->im = UART011_RTIM;
if (!pl011_dma_rx_running(uap))
if (!pl011_dma_rx_running(uap)) {
uap->im |= UART011_RXIM;
} else {
if (uap->vendor->eord_interrupt)
pl011_write(NV_UART011_EORDIM, uap, REG_NV_MIM);
}
pl011_write(uap->im, uap, REG_IMSC);
+16
View File
@@ -94,6 +94,14 @@
#define UART01x_FR_DCD BIT(2)
#define UART01x_FR_DSR BIT(1)
#define UART01x_FR_CTS BIT(0)
/*
* Nvidia Tegra UART supports EORD interrupt through misc registers.
*/
#define NV_UART011_MIS 0x1008 /* MISC interrupt status */
#define NV_UART011_MIM 0x100c /* MISC interrupt mask */
#define NV_UART011_MMIS 0x1010 /* MISC masked interrupt status */
#define NV_UART011_MIC 0x1014 /* MISC interrupt clear */
#define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY)
/*
@@ -208,12 +216,20 @@
#define UART011_CTSMIC BIT(1) /* CTS interrupt clear */
#define UART011_RIMIC BIT(0) /* RI interrupt clear */
/* Values for Nvidia MISC interrupts */
#define NV_UART011_EORDIC (1 << 0) /* EORD interrupt clear */
#define UART011_DMAONERR BIT(2) /* disable dma on error */
#define UART011_TXDMAE BIT(1) /* enable transmit dma */
#define UART011_RXDMAE BIT(0) /* enable receive dma */
#define UART01x_RSR_ANY (UART01x_RSR_OE | UART01x_RSR_BE | UART01x_RSR_PE | UART01x_RSR_FE)
#define UART01x_FR_MODEM_ANY (UART01x_FR_DCD | UART01x_FR_DSR | UART01x_FR_CTS)
/* Values for Nvidia MISC interrupts */
#define NV_UART011_EORDIM (1 << 0) /* EORD interrupt mask */
/* Values for Nvidia MISC interrupts */
#define NV_UART011_EORDIS (1 << 0) /* EORD interrupt status */
#ifndef __ASSEMBLY__
struct amba_device; /* in uncompress this is included but amba/bus.h is not */