aboutsummaryrefslogtreecommitdiffstats
path: root/xen/drivers
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2013-09-20 17:18:35 +0100
committerIan Campbell <ian.campbell@citrix.com>2013-09-21 16:27:45 +0100
commit50417cd978aa54930d065ac1f139f935d14af76d (patch)
tree16c9096142fef419b39c2ad70a47110bb4483e38 /xen/drivers
parent7c1de0038895cbc75ebd0caffc5b0f3f03c5ad51 (diff)
downloadxen-50417cd978aa54930d065ac1f139f935d14af76d.tar.gz
xen-50417cd978aa54930d065ac1f139f935d14af76d.tar.bz2
xen-50417cd978aa54930d065ac1f139f935d14af76d.zip
ns16550: support DesignWare 8250
This hardware has an additional feature which signals an error if you try to write LCR while the UART is busy. We need to clear this error during setup, otherwise LCR.DLAB doesn't get set and we cannot read/write the divisor. This has been tested on the cubieboard2 Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Keir Fraser <keir@xen.org> Cc: jbeulich@suse.com
Diffstat (limited to 'xen/drivers')
-rw-r--r--xen/drivers/char/ns16550.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 45da924381..5892eb7a85 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -61,6 +61,7 @@ static struct ns16550 {
struct timer resume_timer;
unsigned int timeout_ms;
bool_t intr_works;
+ bool_t dw_usr_bsy;
#ifdef HAS_PCI
/* PCI card parameters. */
unsigned int pb_bdf[3]; /* pci bridge BDF */
@@ -237,6 +238,16 @@ static void ns16550_setup_preirq(struct ns16550 *uart)
/* No interrupts. */
ns_write_reg(uart, UART_IER, 0);
+ if ( uart->dw_usr_bsy &&
+ (ns_read_reg(uart, UART_IIR) & UART_IIR_BSY) == UART_IIR_BSY )
+ {
+ /* DesignWare 8250 detects if LCR is written while the UART is
+ * busy and raises a "busy detect" interrupt. Read the UART
+ * Status Register to clear this state.
+ */
+ ns_read_reg(uart, UART_USR);
+ }
+
/* Line control and baud-rate generator. */
ns_write_reg(uart, UART_LCR, lcr | UART_LCR_DLAB);
if ( uart->baud != BAUD_AUTO )
@@ -787,6 +798,8 @@ static int __init ns16550_uart_dt_init(struct dt_device_node *dev,
/* The common bit of the driver mostly deals with irq not dt_irq. */
uart->irq = uart->dt_irq.irq;
+ uart->dw_usr_bsy = dt_device_is_compatible(dev, "snps,dw-apb-uart");
+
uart->vuart.base_addr = uart->io_base;
uart->vuart.size = uart->io_size;
uart->vuart.data_off = UART_THR <<uart->reg_shift;
@@ -804,6 +817,7 @@ static int __init ns16550_uart_dt_init(struct dt_device_node *dev,
static const char const *ns16550_dt_compat[] __initconst =
{
"ns16550",
+ "snps,dw-apb-uart",
NULL
};