From: Chen Baozi <baozich@gmail.com>
To: Ian Campbell <Ian.Campbell@citrix.com>
Cc: Chen Baozi <baozich@gmail.com>, Keir Fraser <keir@xen.org>,
xen-devel@lists.xen.org
Subject: [PATCH 4/4] xen/arm: enable ns16550 uart driver for OMAP5432
Date: Fri, 19 Jul 2013 20:57:46 +0800 [thread overview]
Message-ID: <1374238666-5870-5-git-send-email-baozich@gmail.com> (raw)
In-Reply-To: <1374238666-5870-1-git-send-email-baozich@gmail.com>
Signed-off-by: Chen Baozi <baozich@gmail.com>
---
xen/arch/arm/Rules.mk | 1 +
xen/drivers/char/ns16550.c | 155 +++++++++++++++++++++++++++++++++++++++------
xen/include/asm-arm/io.h | 49 ++++++++++++++
xen/include/xen/serial.h | 7 +-
4 files changed, 191 insertions(+), 21 deletions(-)
diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk
index eaa03fb..8604e34 100644
--- a/xen/arch/arm/Rules.mk
+++ b/xen/arch/arm/Rules.mk
@@ -9,6 +9,7 @@
HAS_DEVICE_TREE := y
HAS_VIDEO := y
HAS_ARM_HDLCD := y
+HAS_NS16550 := y
CFLAGS += -fno-builtin -fno-common -Wredundant-decls
CFLAGS += -iwithprefix include -Werror -Wno-pointer-arith -pipe
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 60512be..b8690eb 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -1,10 +1,10 @@
/******************************************************************************
* ns16550.c
- *
+ *
* Driver for 16550-series UARTs. This driver is to be kept within Xen as
* it permits debugging of seriously-toasted machines (e.g., in situations
* where a device driver within a guest OS would be inaccessible).
- *
+ *
* Copyright (c) 2003-2005, K A Fraser
*/
@@ -25,6 +25,13 @@
#include <asm/fixmap.h>
#endif
+#ifdef CONFIG_ARM
+#include <xen/device_tree.h>
+#include <xen/errno.h>
+#include <asm/early_printk.h>
+#include <asm/device.h>
+#endif
+
/*
* Configure serial port with a string:
* <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>[,<port-bdf>[,<bridge-bdf>]]]]].
@@ -39,8 +46,11 @@ string_param("com1", opt_com1);
string_param("com2", opt_com2);
static struct ns16550 {
- int baud, clock_hz, data_bits, parity, stop_bits, fifo_size, irq;
- unsigned long io_base; /* I/O port or memory-mapped I/O address. */
+ int baud, data_bits, parity, stop_bits, fifo_size;
+ u32 clock_hz;
+ struct dt_irq irq;
+ u64 io_base; /* I/O port or memory-mapped I/O address. */
+ u64 io_size;
char __iomem *remapped_io_base; /* Remapped virtual address of MMIO. */
/* UART with IRQ line: interrupt-driven I/O. */
struct irqaction irqaction;
@@ -61,16 +71,24 @@ static struct ns16550 {
static char ns_read_reg(struct ns16550 *uart, int reg)
{
+#ifdef CONFIG_X86
if ( uart->remapped_io_base == NULL )
return inb(uart->io_base + reg);
return readb(uart->remapped_io_base + reg);
+#else
+ return readb(uart->remapped_io_base + (reg << 2));
+#endif
}
static void ns_write_reg(struct ns16550 *uart, int reg, char c)
{
+#ifdef CONFIG_X86
if ( uart->remapped_io_base == NULL )
return outb(c, uart->io_base + reg);
writeb(c, uart->remapped_io_base + reg);
+#else
+ writeb(c, uart->remapped_io_base + (reg << 2));
+#endif
}
static void ns16550_interrupt(
@@ -145,11 +163,12 @@ static int ns16550_getc(struct serial_port *port, char *pc)
return 1;
}
+#ifdef CONFIG_X86
static void pci_serial_early_init(struct ns16550 *uart)
{
if ( !uart->ps_bdf_enable || uart->io_base >= 0x10000 )
return;
-
+
if ( uart->pb_bdf_enable )
pci_conf_write16(0, uart->pb_bdf[0], uart->pb_bdf[1], uart->pb_bdf[2],
PCI_IO_BASE,
@@ -161,7 +180,13 @@ static void pci_serial_early_init(struct ns16550 *uart)
uart->io_base | PCI_BASE_ADDRESS_SPACE_IO);
pci_conf_write16(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
PCI_COMMAND, PCI_COMMAND_IO);
+
+}
+#else
+static void pci_serial_early_init(struct ns16550 *uart)
+{
}
+#endif
static void ns16550_setup_preirq(struct ns16550 *uart)
{
@@ -217,7 +242,9 @@ static void __init ns16550_init_preirq(struct serial_port *port)
uart->remapped_io_base = (void __iomem *)fix_to_virt(idx);
uart->remapped_io_base += uart->io_base & ~PAGE_MASK;
#else
- uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
+ uart->remapped_io_base = ioremap_attr(uart->io_base,
+ uart->io_size,
+ PAGE_HYPERVISOR_NOCACHE);
#endif
}
@@ -231,7 +258,7 @@ static void __init ns16550_init_preirq(struct serial_port *port)
static void ns16550_setup_postirq(struct ns16550 *uart)
{
- if ( uart->irq > 0 )
+ if ( uart->irq.irq > 0 )
{
/* Master interrupt enable; also keep DTR/RTS asserted. */
ns_write_reg(uart,
@@ -241,7 +268,7 @@ static void ns16550_setup_postirq(struct ns16550 *uart)
ns_write_reg(uart, UART_IER, UART_IER_ERDAI | UART_IER_ELSI);
}
- if ( uart->irq >= 0 )
+ if ( uart->irq.irq >= 0 )
set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
}
@@ -250,7 +277,7 @@ static void __init ns16550_init_postirq(struct serial_port *port)
struct ns16550 *uart = port->uart;
int rc, bits;
- if ( uart->irq < 0 )
+ if ( uart->irq.irq < 0 )
return;
serial_async_transmit(port);
@@ -262,20 +289,26 @@ static void __init ns16550_init_postirq(struct serial_port *port)
uart->timeout_ms = max_t(
unsigned int, 1, (bits * uart->fifo_size * 1000) / uart->baud);
- if ( uart->irq > 0 )
+ if ( uart->irq.irq > 0 )
{
uart->irqaction.handler = ns16550_interrupt;
uart->irqaction.name = "ns16550";
uart->irqaction.dev_id = port;
- if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
- printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
+#ifdef CONFIG_X86
+ if ( (rc = setup_irq(uart->irq.irq, &uart->irqaction)) != 0 )
+#else
+ if ( (rc = setup_dt_irq(&uart->irq, &uart->irqaction)) != 0 )
+#endif
+ printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq.irq);
}
ns16550_setup_postirq(uart);
+#ifdef CONFIG_X86
if ( uart->bar || uart->ps_bdf_enable )
pci_hide_device(uart->ps_bdf[0], PCI_DEVFN(uart->ps_bdf[1],
uart->ps_bdf[2]));
+#endif
}
static void ns16550_suspend(struct serial_port *port)
@@ -284,13 +317,16 @@ static void ns16550_suspend(struct serial_port *port)
stop_timer(&uart->timer);
+#ifdef CONFIG_X86
if ( uart->bar )
uart->cr = pci_conf_read16(0, uart->ps_bdf[0], uart->ps_bdf[1],
uart->ps_bdf[2], PCI_COMMAND);
+#endif
}
static void _ns16550_resume(struct serial_port *port)
{
+#ifdef CONFIG_X86
struct ns16550 *uart = port->uart;
if ( uart->bar )
@@ -300,6 +336,7 @@ static void _ns16550_resume(struct serial_port *port)
pci_conf_write16(0, uart->ps_bdf[0], uart->ps_bdf[1], uart->ps_bdf[2],
PCI_COMMAND, uart->cr);
}
+#endif
ns16550_setup_preirq(port->uart);
ns16550_setup_postirq(port->uart);
@@ -370,9 +407,17 @@ static void __init ns16550_endboot(struct serial_port *port)
static int __init ns16550_irq(struct serial_port *port)
{
struct ns16550 *uart = port->uart;
- return ((uart->irq > 0) ? uart->irq : -1);
+ return ((uart->irq.irq > 0) ? uart->irq.irq : -1);
}
+#ifdef CONFIG_ARM
+static const struct dt_irq __init *ns16550_dt_irq(struct serial_port *port)
+{
+ struct ns16550 *uart = port->uart;
+ return &uart->irq;
+}
+#endif
+
static struct uart_driver __read_mostly ns16550_driver = {
.init_preirq = ns16550_init_preirq,
.init_postirq = ns16550_init_postirq,
@@ -382,7 +427,10 @@ static struct uart_driver __read_mostly ns16550_driver = {
.tx_ready = ns16550_tx_ready,
.putc = ns16550_putc,
.getc = ns16550_getc,
- .irq = ns16550_irq
+ .irq = ns16550_irq,
+#ifdef CONFIG_ARM
+ .dt_irq_get = ns16550_dt_irq
+#endif
};
static int __init parse_parity_char(int c)
@@ -403,6 +451,7 @@ static int __init parse_parity_char(int c)
return 0;
}
+#ifdef CONFIG_X86
static void __init parse_pci_bdf(const char **conf, unsigned int bdf[3])
{
bdf[0] = simple_strtoul(*conf, conf, 16);
@@ -415,6 +464,7 @@ static void __init parse_pci_bdf(const char **conf, unsigned int bdf[3])
(*conf)++;
bdf[2] = simple_strtoul(*conf, conf, 16);
}
+#endif
static int __init check_existence(struct ns16550 *uart)
{
@@ -428,7 +478,7 @@ static int __init check_existence(struct ns16550 *uart)
return 1;
pci_serial_early_init(uart);
-
+
/*
* Do a simple existence test first; if we fail this,
* there's no point trying anything else.
@@ -445,7 +495,7 @@ static int __init check_existence(struct ns16550 *uart)
scratch3 = ns_read_reg(uart, UART_IER) & 0x0f;
ns_write_reg(uart, UART_IER, scratch);
if ( (scratch2 != 0) || (scratch3 != 0x0F) )
- return 0;
+ return 0;
/*
* Check to see if a UART is really there.
@@ -456,6 +506,7 @@ static int __init check_existence(struct ns16550 *uart)
return (status == 0x90);
}
+#ifdef CONFIG_X86
static int
pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
{
@@ -507,7 +558,7 @@ pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
uart->bar = bar;
uart->bar_idx = bar_idx;
uart->io_base = bar & ~PCI_BASE_ADDRESS_SPACE_IO;
- uart->irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ?
+ uart->irq.irq = pci_conf_read8(0, b, d, f, PCI_INTERRUPT_PIN) ?
pci_conf_read8(0, b, d, f, PCI_INTERRUPT_LINE) : 0;
return 0;
@@ -519,11 +570,12 @@ pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
return -1;
uart->io_base = 0x3f8;
- uart->irq = 0;
+ uart->irq.irq = 0;
uart->clock_hz = UART_CLOCK_HZ;
return 0;
}
+#endif
#define PARSE_ERR(_f, _a...) \
do { \
@@ -534,6 +586,7 @@ pci_uart_config (struct ns16550 *uart, int skip_amt, int bar_idx)
static void __init ns16550_parse_port_config(
struct ns16550 *uart, const char *conf)
{
+#ifdef CONFIG_X86
int baud;
/* No user-specified configuration? */
@@ -589,7 +642,7 @@ static void __init ns16550_parse_port_config(
}
if ( *conf == ',' && *++conf != ',' )
- uart->irq = simple_strtol(conf, &conf, 10);
+ uart->irq.irq = simple_strtol(conf, &conf, 10);
if ( *conf == ',' && *++conf != ',' )
{
@@ -604,6 +657,8 @@ static void __init ns16550_parse_port_config(
}
config_parsed:
+#endif
+
/* Sanity checks. */
if ( (uart->baud != BAUD_AUTO) &&
((uart->baud < 1200) || (uart->baud > 115200)) )
@@ -633,18 +688,80 @@ void __init ns16550_init(int index, struct ns16550_defaults *defaults)
uart->baud = (defaults->baud ? :
console_has((index == 0) ? "com1" : "com2")
? BAUD_AUTO : 0);
+#ifdef CONFIG_ARM
+ uart->clock_hz = defaults->clock_hz;
+#else
uart->clock_hz = UART_CLOCK_HZ;
+#endif
uart->data_bits = defaults->data_bits;
uart->parity = parse_parity_char(defaults->parity);
uart->stop_bits = defaults->stop_bits;
uart->irq = defaults->irq;
uart->io_base = defaults->io_base;
+#ifdef CONFIG_ARM
+ uart->io_size = defaults->io_size;
+#endif
+
/* Default is no transmit FIFO. */
uart->fifo_size = 1;
ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
+
}
+#ifdef CONFIG_ARM
+
+static int __init ns16550_dt_init(struct dt_device_node *dev,
+ const void *data)
+{
+ struct ns16550_defaults uart;
+ int res;
+ const __be32 *clkspec;
+
+ uart.baud = 115200;
+ uart.data_bits = 8;
+ uart.parity = 'n';
+ uart.stop_bits = 1;
+
+ res = dt_device_get_address(dev, 0, &uart.io_base, &uart.io_size);
+ if (res) {
+ early_printk("ns16550: Unable to retrieve the base"
+ " address of the UART\n");
+ return res;
+ }
+
+ res = dt_device_get_irq(dev, 0, &uart.irq);
+ if (res) {
+ early_printk("ns16550: Unable to retrieve the IRQ\n");
+ return res;
+ }
+
+ clkspec = dt_get_property(dev, "clock-frequency", NULL);
+ if (clkspec == NULL) {
+ early_printk("ns16550: Unable to retrieve the clock frequency\n");
+ return -EINVAL;
+ }
+ uart.clock_hz = be32_to_cpup(clkspec);
+
+ ns16550_init(0, &uart);
+ dt_device_set_used_by(dev, DOMID_XEN);
+
+ return 0;
+}
+
+static const char const *ns16550_dt_compat[] __initdata =
+{
+ "ti,omap4-uart",
+ NULL
+};
+
+DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
+ .compatible = ns16550_dt_compat,
+ .init = ns16550_dt_init,
+DT_DEVICE_END
+
+#endif /* CONFIG_ARM */
+
/*
* Local variables:
* mode: C
diff --git a/xen/include/asm-arm/io.h b/xen/include/asm-arm/io.h
index aea5233..33674bc 100644
--- a/xen/include/asm-arm/io.h
+++ b/xen/include/asm-arm/io.h
@@ -1,6 +1,55 @@
#ifndef _ASM_IO_H
#define _ASM_IO_H
+static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
+{
+ asm volatile("strb %1, %0"
+ : "+Qo" (*(volatile u8 __force *)addr)
+ : "r" (val));
+}
+
+static inline void __raw_writel(u32 val, volatile void __iomem *addr)
+{
+ asm volatile("str %1, %0"
+ : "+Qo" (*(volatile u32 __force *)addr)
+ : "r" (val));
+}
+
+static inline u8 __raw_readb(const volatile void __iomem *addr)
+{
+ u8 val;
+ asm volatile("ldrb %1, %0"
+ : "+Qo" (*(volatile u8 __force *)addr),
+ "=r" (val));
+ return val;
+}
+
+static inline u32 __raw_readl(const volatile void __iomem *addr)
+{
+ u32 val;
+ asm volatile("ldr %1, %0"
+ : "+Qo" (*(volatile u32 __force *)addr),
+ "=r" (val));
+ return val;
+}
+
+#define __iormb() rmb()
+#define __iowmb() wmb()
+
+#define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; })
+#define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \
+ __raw_readl(c)); __r; })
+
+#define writeb_relaxed(v,c) __raw_writeb(v,c)
+#define writel_relaxed(v,c) __raw_writel((__force u32) cpu_to_le32(v),c)
+
+#define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; })
+#define readl(c) ({ u32 __v = readl_relaxed(c); __iormb(); __v; })
+
+#define writeb(v,c) ({ __iowmb(); writeb_relaxed(v,c); })
+#define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); })
+
+
#endif
/*
* Local variables:
diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
index 9caf776..09ca855 100644
--- a/xen/include/xen/serial.h
+++ b/xen/include/xen/serial.h
@@ -11,6 +11,7 @@
#include <xen/init.h>
#include <xen/spinlock.h>
+#include <xen/device_tree.h>
struct cpu_user_regs;
@@ -151,8 +152,10 @@ struct ns16550_defaults {
int data_bits; /* default data bits (5, 6, 7 or 8) */
int parity; /* default parity (n, o, e, m or s) */
int stop_bits; /* default stop bits (1 or 2) */
- int irq; /* default irq */
- unsigned long io_base; /* default io_base address */
+ struct dt_irq irq; /* default irq */
+ u64 io_base; /* default io_base address */
+ u64 io_size;
+ u32 clock_hz; /* UART clock rate */
};
void ns16550_init(int index, struct ns16550_defaults *defaults);
void ehci_dbgp_init(void);
--
1.8.1.4
next prev parent reply other threads:[~2013-07-19 12:57 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-19 12:57 [PATCH 0/4] Support 8250 compatible UART for OMAP5432 Chen Baozi
2013-07-19 12:57 ` [PATCH 1/4] xen: extract register definitions from ns16550 into a separated header Chen Baozi
2013-07-19 15:35 ` Julien Grall
2013-07-19 15:37 ` Chen Baozi
2013-07-19 15:43 ` Julien Grall
2013-07-19 12:57 ` [PATCH 2/4] xen/arm: add OMAP5432 UART support for early_printk Chen Baozi
2013-07-19 15:49 ` Julien Grall
2013-07-19 12:57 ` [PATCH 3/4] xen: set the right flags when enabling interrupts for 8250 Chen Baozi
2013-07-19 14:15 ` Ian Campbell
2013-07-19 15:18 ` Chen Baozi
2013-07-22 12:59 ` Chen Baozi
2013-07-23 11:47 ` Chen Baozi
2013-07-24 10:04 ` Chen Baozi
2013-07-25 9:14 ` Chen Baozi
2013-07-25 11:17 ` Julien Grall
2013-07-25 11:31 ` Chen Baozi
2013-07-25 12:33 ` Julien Grall
2013-07-26 1:14 ` Chen Baozi
2013-07-26 3:31 ` Chen Baozi
2013-07-26 9:30 ` Chen Baozi
2013-07-26 10:42 ` Julien Grall
2013-07-26 11:01 ` Chen Baozi
2013-07-26 12:01 ` Julien Grall
2013-07-26 12:32 ` Chen Baozi
2013-07-19 12:57 ` Chen Baozi [this message]
2013-07-19 17:06 ` [PATCH 4/4] xen/arm: enable ns16550 uart driver for OMAP5432 Julien Grall
2013-07-22 13:06 ` Chen Baozi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1374238666-5870-5-git-send-email-baozich@gmail.com \
--to=baozich@gmail.com \
--cc=Ian.Campbell@citrix.com \
--cc=keir@xen.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).