@@ -505,10 +505,6 @@ void gic_route_spis(void)
int seridx;
const struct dt_irq *irq;
- /* XXX should get these from DT */
- /* UART */
- gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0);
-
for ( seridx = 0; seridx <= SERHND_IDX; seridx++ )
{
if ( (irq = serial_dt_irq(seridx)) == NULL )
@@ -433,10 +433,6 @@ void __init start_xen(unsigned long boot_phys_offset,
dt_unflatten_host_device_tree();
dt_irq_xlate = gic_irq_xlate;
-#ifdef EARLY_UART_ADDRESS
- /* TODO Need to get device tree or command line for UART address */
- pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE));
-#endif
dt_uart_init();
console_init_preirq();
@@ -22,9 +22,16 @@
#include <xen/serial.h>
#include <xen/init.h>
#include <xen/irq.h>
+#include <asm/early_printk.h>
+#include <xen/device_tree.h>
+#include <xen/errno.h>
+#include <asm/device.h>
+#include <xen/mm.h>
+#include <xen/vmap.h>
static struct pl011 {
- unsigned int baud, clock_hz, data_bits, parity, stop_bits, irq;
+ unsigned int baud, clock_hz, data_bits, parity, stop_bits;
+ struct dt_irq irq;
volatile uint32_t *regs;
/* UART with IRQ line: interrupt-driven I/O. */
struct irqaction irqaction;
@@ -32,7 +39,7 @@ static struct pl011 {
/* struct timer timer; */
/* unsigned int timeout_ms; */
/* bool_t probing, intr_works; */
-} pl011_com[2] = {{0}};
+} pl011_com = {0};
/* PL011 register addresses */
#define DR (0x00/4)
@@ -163,13 +170,13 @@ static void __init pl011_init_postirq(struct serial_port *port)
struct pl011 *uart = port->uart;
int rc;
- if ( uart->irq > 0 )
+ if ( uart->irq.irq > 0 )
{
uart->irqaction.handler = pl011_interrupt;
uart->irqaction.name = "pl011";
uart->irqaction.dev_id = port;
- if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
- printk("ERROR: Failed to allocate pl011 IRQ %d\n", uart->irq);
+ if ( (rc = setup_dt_irq(&uart->irq, &uart->irqaction)) != 0 )
+ printk("ERROR: Failed to allocate pl011 IRQ %d\n", uart->irq.irq);
}
/* Clear pending error interrupts */
@@ -215,7 +222,14 @@ static int pl011_getc(struct serial_port *port, char *pc)
static int __init pl011_irq(struct serial_port *port)
{
struct pl011 *uart = port->uart;
- return ((uart->irq > 0) ? uart->irq : -1);
+ return ((uart->irq.irq > 0) ? uart->irq.irq : -1);
+}
+
+static const struct dt_irq __init *pl011_dt_irq(struct serial_port *port)
+{
+ struct pl011 *uart = port->uart;
+
+ return &uart->irq;
}
static struct uart_driver __read_mostly pl011_driver = {
@@ -227,32 +241,68 @@ static struct uart_driver __read_mostly pl011_driver = {
.tx_ready = pl011_tx_ready,
.putc = pl011_putc,
.getc = pl011_getc,
- .irq = pl011_irq
+ .irq = pl011_irq,
+ .dt_irq_get = pl011_dt_irq,
};
-/* TODO: Parse UART config from device-tree or command-line */
-
-void __init pl011_init(int index, unsigned long register_base_address)
+/* TODO: Parse UART config from the command line */
+static int __init pl011_uart_init(struct dt_device_node *dev,
+ const void *data)
{
struct pl011 *uart;
+ int res;
+ u64 addr, size;
- if ( (index < 0) || (index > 1) )
- return;
-
- uart = &pl011_com[index];
+ uart = &pl011_com;
uart->clock_hz = 0x16e3600;
uart->baud = 38400;
uart->data_bits = 8;
uart->parity = PARITY_NONE;
uart->stop_bits = 1;
- uart->irq = 37; /* TODO Need to find this from devicetree */
- uart->regs = (uint32_t *) register_base_address;
+
+ res = dt_device_get_address(dev, 0, &addr, &size);
+ if ( res )
+ {
+ early_printk("pl011: Unable to retrieve the base"
+ " address of the UART\n");
+ return res;
+ }
+
+ uart->regs = ioremap_attr(addr, size, PAGE_HYPERVISOR_NOCACHE);
+ if ( !uart->regs )
+ {
+ early_printk("pl011: Unable to map the UART memory\n");
+
+ return -ENOMEM;
+ }
+
+ res = dt_device_get_irq(dev, 0, &uart->irq);
+ if ( res )
+ {
+ early_printk("pl011: Unable to retrieve the IRQ\n");
+ return res;
+ }
/* Register with generic serial driver. */
- serial_register_uart(uart - pl011_com, &pl011_driver, uart);
+ serial_register_uart(SERHND_DTUART, &pl011_driver, uart);
+
+ dt_device_set_used_by(dev, DOMID_XEN);
+
+ return 0;
}
+static const char const *pl011_dt_compat[] __initdata =
+{
+ "arm,pl011",
+ NULL
+};
+
+DT_DEVICE_START(pl011, "PL011 UART", DEVICE_SERIAL)
+ .compatible = pl011_dt_compat,
+ .init = pl011_uart_init,
+DT_DEVICE_END
+
/*
* Local variables:
* mode: C
@@ -157,7 +157,6 @@ struct ns16550_defaults {
void ns16550_init(int index, struct ns16550_defaults *defaults);
void ehci_dbgp_init(void);
-void pl011_init(int index, unsigned long register_base_address);
void __init dt_uart_init(void);
struct physdev_dbgp_op;
Allow UART driver to retrieve all its information in the device tree. It's possible to choose the pl011 driver via the Xen command line. Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v3: - Remove the usage of serial_arm_defaults - Get the base address from the DT and map it with ioremap_attr - Allow only 1 PL011 assigned to SERHND_DTUART - Replace DT_USED_BY_XEN by DOMID_XEN Changes in v2: - Rework TODO - Use the new function setup_dt_irq --- xen/arch/arm/gic.c | 4 --- xen/arch/arm/setup.c | 4 --- xen/drivers/char/pl011.c | 84 ++++++++++++++++++++++++++++++++++++---------- xen/include/xen/serial.h | 1 - 4 files changed, 67 insertions(+), 26 deletions(-)