diff mbox

[V3,36/41] xen/arm: Don't use pl011 UART by default for early printk

Message ID 1368152307-598-37-git-send-email-julien.grall@linaro.org
State Superseded, archived
Headers show

Commit Message

Julien Grall May 10, 2013, 2:18 a.m. UTC
Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user
to choose if he wants to have early output, ie before the console is initialized.

This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled,
Xen will only be able to run on a board with this UART.

If a developper wants to add support for a new UART, he must implement the
following assembly macro/define:
   - EALY_UART_BASE_ADDRESS: variable which contains the physical base address
   for the UART
   - early_uart_init: initialize the UART
   - early_uart_ready: check and wait until the UART can transmit a new
   character
   - early_uart_transmit: transmit a character

For more details about the parameters of each function,
see arm{32,64}/debug-pl011.inc comments.

Signed-off-by: Julien Grall <julien.grall@linaro.org>

Changes in v3:
    - Fix clobbers list in UART functions
    - Remove obj-$(CONFIG_EARLY_PL011) in arm32/Makefile. Was unused.
    - Set EARLY_PRINTK to y only if EARLY_DEBUG_INC is not null. Will
    avoid redundant line per early printk machine

Changes in v2:
    - Use macro instead of function for assembly early printk API
    - Add documentation for ARM early printk
---
 docs/misc/arm/early-printk.txt     |   14 ++++++++
 xen/arch/arm/Makefile              |    2 +-
 xen/arch/arm/Rules.mk              |   18 ++++++++++
 xen/arch/arm/arm32/Makefile        |    4 ++-
 xen/arch/arm/arm32/debug-pl011.inc |   58 ++++++++++++++++++++++++++++++
 xen/arch/arm/arm32/debug.S         |   33 +++++++++++++++++
 xen/arch/arm/arm32/head.S          |   65 ++++++++++++++++-----------------
 xen/arch/arm/arm64/Makefile        |    2 ++
 xen/arch/arm/arm64/debug-pl011.inc |   59 ++++++++++++++++++++++++++++++
 xen/arch/arm/arm64/debug.S         |   33 +++++++++++++++++
 xen/arch/arm/arm64/head.S          |   69 ++++++++++++++++--------------------
 xen/arch/arm/early_printk.c        |   16 +--------
 xen/include/asm-arm/config.h       |    2 --
 xen/include/asm-arm/early_printk.h |    2 +-
 14 files changed, 285 insertions(+), 92 deletions(-)
 create mode 100644 docs/misc/arm/early-printk.txt
 create mode 100644 xen/arch/arm/arm32/debug-pl011.inc
 create mode 100644 xen/arch/arm/arm32/debug.S
 create mode 100644 xen/arch/arm/arm64/debug-pl011.inc
 create mode 100644 xen/arch/arm/arm64/debug.S

Comments

Ian Campbell May 10, 2013, 9:46 a.m. UTC | #1
On Fri, 2013-05-10 at 03:18 +0100, Julien Grall wrote:
> Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user
> to choose if he wants to have early output, ie before the console is initialized.
> 
> This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled,
> Xen will only be able to run on a board with this UART.
> 
> If a developper wants to add support for a new UART, he must implement the
> following assembly macro/define:
>    - EALY_UART_BASE_ADDRESS: variable which contains the physical base address
>    for the UART
>    - early_uart_init: initialize the UART
>    - early_uart_ready: check and wait until the UART can transmit a new
>    character
>    - early_uart_transmit: transmit a character
> 
> For more details about the parameters of each function,
> see arm{32,64}/debug-pl011.inc comments.
> 
> Signed-off-by: Julien Grall <julien.grall@linaro.org>

Acked-by: Ian Campbell <ian.campbell@citrix.com>
diff mbox

Patch

diff --git a/docs/misc/arm/early-printk.txt b/docs/misc/arm/early-printk.txt
new file mode 100644
index 0000000..4065811
--- /dev/null
+++ b/docs/misc/arm/early-printk.txt
@@ -0,0 +1,14 @@ 
+How to enable early printk
+
+Early printk can only be enabled if debug=y. You may want to enable it if
+you are debbuging code that executes before the console is initialized.
+
+Note that selecting this option will limit Xen to a single UART definition.
+Attempting to boot Xen image on a different platform *will not work*, so this
+option should not be enable for Xens that are intended to be portable.
+
+CONFIG_EARLY_PRINTK=mach
+where mach is the name of the machine:
+  - vexpress: printk with pl011 for versatile express
+
+By default early printk is disabled.
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 2717f26..87fabe1 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -2,7 +2,7 @@  subdir-$(arm32) += arm32
 subdir-$(arm64) += arm64
 subdir-y += platforms
 
-obj-y += early_printk.o
+obj-$(EARLY_PRINTK) += early_printk.o
 obj-y += cpu.o
 obj-y += domain.o
 obj-y += psci.o
diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk
index a0a14e0..297385b 100644
--- a/xen/arch/arm/Rules.mk
+++ b/xen/arch/arm/Rules.mk
@@ -36,3 +36,21 @@  endif
 ifneq ($(call cc-option,$(CC),-fvisibility=hidden,n),n)
 CFLAGS += -DGCC_HAS_VISIBILITY_ATTRIBUTE
 endif
+
+EARLY_PRINTK := n
+
+ifeq ($(debug),y)
+
+# Early printk for versatile express
+# TODO handle UART base address from make command line
+ifeq ($(CONFIG_EARLY_PRINTK), vexpress)
+EARLY_PRINTK_INC := pl011
+endif
+
+ifneq ($(EARLY_PRINTK_INC),)
+EARLY_PRINTK := y
+endif
+
+CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK
+CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK_INC=\"debug-$(EARLY_PRINTK_INC).inc\"
+endif
diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile
index 1ad3364..aaf277a 100644
--- a/xen/arch/arm/arm32/Makefile
+++ b/xen/arch/arm/arm32/Makefile
@@ -5,4 +5,6 @@  obj-y += mode_switch.o
 obj-y += proc-ca15.o
 
 obj-y += traps.o
-obj-y += domain.o
\ No newline at end of file
+obj-y += domain.o
+
+obj-$(EARLY_PRINTK) += debug.o
diff --git a/xen/arch/arm/arm32/debug-pl011.inc b/xen/arch/arm/arm32/debug-pl011.inc
new file mode 100644
index 0000000..6954aeb
--- /dev/null
+++ b/xen/arch/arm/arm32/debug-pl011.inc
@@ -0,0 +1,58 @@ 
+/*
+ * xen/arch/arm/arm32/debug-pl011.inc
+ *
+ * PL011 specific debug code
+ *
+ * Copyright (c) 2013 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define EARLY_UART_BASE_ADDRESS 0x1c090000
+
+/* PL011 UART initialization
+ * rb: register which contains the UART base address
+ * rc: scratch register 1
+ * rd: scratch register 2 (unused here) */
+.macro early_uart_init rb, rc, rd
+        mov   \rc, #0x0
+        str   \rc, [\rb, #0x28]     /* -> UARTFBRD (Baud divisor fraction) */
+        mov   \rc, #0x4             /* 7.3728MHz / 0x4 == 16 * 115200 */
+        str   \rc, [\rb, #0x24]     /* -> UARTIBRD (Baud divisor integer) */
+        mov   \rc, #0x60            /* 8n1 */
+        str   \rc, [\rb, #0x2C]     /* -> UARTLCR_H (Line control) */
+        ldr   \rc, =0x00000301      /* RXE | TXE | UARTEN */
+        str   \rc, [\rb, #0x30]     /* -> UARTCR (Control Register) */
+.endm
+
+/* PL011 UART wait UART to be ready to transmit
+ * rb: register which contains the UART base address
+ * rc: scratch register */
+.macro early_uart_ready rb, rc
+1:
+        ldr   \rc, [\rb, #0x18]     /* <- UARTFR (Flag register) */
+        tst   \rc, #0x8             /* Check BUSY bit */
+        bne   1b                    /* Wait for the UART to be ready */
+.endm
+
+/* PL011 UART transmit character
+ * rb: register which contains the UART base address
+ * rt: register which contains the character to transmit */
+.macro early_uart_transmit rb, rt
+        str   \rt, [\rb]            /* -> UARTDR (Data Register) */
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm32/debug.S b/xen/arch/arm/arm32/debug.S
new file mode 100644
index 0000000..09e5cae
--- /dev/null
+++ b/xen/arch/arm/arm32/debug.S
@@ -0,0 +1,33 @@ 
+/*
+ * xen/arch/arm/arm32/debug.S
+ *
+ * Wrapper for early printk
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/config.h>
+
+#ifdef EARLY_PRINTK_INC
+#include EARLY_PRINTK_INC
+#endif
+
+.globl early_putch
+/* Print a character on the UART - this function is called by C
+ * r0: character to print */
+early_putch:
+        ldr   r1, =FIXMAP_ADDR(FIXMAP_CONSOLE)  /* r1 := VA UART base address */
+        early_uart_ready r1, r2
+        early_uart_transmit r1, r0
+        mov   pc, lr
diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S
index 0b4cfde..d452b59 100644
--- a/xen/arch/arm/arm32/head.S
+++ b/xen/arch/arm/arm32/head.S
@@ -32,9 +32,13 @@ 
 #define PT_UPPER(x) (PT_##x & 0xf00)
 #define PT_LOWER(x) (PT_##x & 0x0ff)
 
+#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC))
+#include EARLY_PRINTK_INC
+#endif
+
 /* Macro to print a string to the UART, if there is one.
  * Clobbers r0-r3. */
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
 #define PRINT(_s)       \
         adr   r0, 98f ; \
         bl    puts    ; \
@@ -42,9 +46,9 @@ 
 98:     .asciz _s     ; \
         .align 2      ; \
 99:
-#else
+#else /* EARLY_PRINTK */
 #define PRINT(s)
-#endif
+#endif /* !EARLY_PRINTK */
 
         .arm
 
@@ -106,8 +110,8 @@  past_zImage:
         bne   1b
 
 boot_cpu:
-#ifdef EARLY_UART_ADDRESS
-        ldr   r11, =EARLY_UART_ADDRESS  /* r11 := UART base address */
+#ifdef EARLY_PRINTK
+        ldr   r11, =EARLY_UART_BASE_ADDRESS  /* r11 := UART base address */
         teq   r12, #0                   /* CPU 0 sets up the UART too */
         bleq  init_uart
         PRINT("- CPU ")
@@ -216,7 +220,7 @@  skip_bss:
         bne   pt_ready
 
         /* console fixmap */
-#ifdef EARLY_UART_ADDRESS
+#if defined(EARLY_PRINTK)
         ldr   r1, =xen_fixmap
         add   r1, r1, r10            /* r1 := paddr (xen_fixmap) */
         mov   r3, #0
@@ -279,7 +283,7 @@  pt_ready:
 paging:
 
 
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
         /* Use a virtual address to access the UART. */
         ldr   r11, =FIXMAP_ADDR(FIXMAP_CONSOLE)
 #endif
@@ -345,49 +349,42 @@  fail:   PRINT("- Boot failed -\r\n")
 1:      wfe
         b     1b
 
-#ifdef EARLY_UART_ADDRESS
 
-/* Bring up the UART. Specific to the PL011 UART.
+#ifdef EARLY_PRINTK
+/* Bring up the UART.
+ * r11: Early UART base address
  * Clobbers r0-r2 */
 init_uart:
-        mov   r1, #0x0
-        str   r1, [r11, #0x28]       /* -> UARTFBRD (Baud divisor fraction) */
-        mov   r1, #0x4               /* 7.3728MHz / 0x4 == 16 * 115200 */
-        str   r1, [r11, #0x24]       /* -> UARTIBRD (Baud divisor integer) */
-        mov   r1, #0x60              /* 8n1 */
-        str   r1, [r11, #0x2C]       /* -> UARTLCR_H (Line control) */
-        ldr   r1, =0x00000301        /* RXE | TXE | UARTEN */
-        str   r1, [r11, #0x30]       /* -> UARTCR (Control Register) */
+        early_uart_init r11, r1, r2
         adr   r0, 1f
-        b     puts
+        b     puts                  /* Jump to puts */
 1:      .asciz "- UART enabled -\r\n"
         .align 4
 
-/* Print early debug messages.  Specific to the PL011 UART.
+/* Print early debug messages.
  * r0: Nul-terminated string to print.
- * Clobbers r0-r2 */
+ * r11: Early UART base address
+ * Clobbers r0-r1 */
 puts:
-        ldr   r2, [r11, #0x18]       /* <- UARTFR (Flag register) */
-        tst   r2, #0x8               /* Check BUSY bit */
-        bne   puts                   /* Wait for the UART to be ready */
-        ldrb  r2, [r0], #1           /* Load next char */
-        teq   r2, #0                 /* Exit on nul */
+        early_uart_ready r11, r1
+        ldrb  r1, [r0], #1           /* Load next char */
+        teq   r1, #0                 /* Exit on nul */
         moveq pc, lr
-        str   r2, [r11]              /* -> UARTDR (Data Register) */
-        b     puts
+        early_uart_transmit r11, r1
+        b puts
 
 /* Print a 32-bit number in hex.  Specific to the PL011 UART.
  * r0: Number to print.
- * clobbers r0-r3 */
+ * r11: Early UART base address
+ * Clobbers r0-r3 */
 putn:
         adr   r1, hex
         mov   r3, #8
-1:      ldr   r2, [r11, #0x18]       /* <- UARTFR (Flag register) */
-        tst   r2, #0x8               /* Check BUSY bit */
-        bne   1b                     /* Wait for the UART to be ready */
+1:
+        early_uart_ready r11, r2
         and   r2, r0, #0xf0000000    /* Mask off the top nybble */
         ldrb  r2, [r1, r2, lsr #28]  /* Convert to a char */
-        str   r2, [r11]              /* -> UARTDR (Data Register) */
+        early_uart_transmit r11, r2
         lsl   r0, #4                 /* Roll it through one nybble at a time */
         subs  r3, r3, #1
         bne   1b
@@ -396,7 +393,7 @@  putn:
 hex:    .ascii "0123456789abcdef"
         .align 2
 
-#else  /* EARLY_UART_ADDRESS */
+#else  /* EARLY_PRINTK */
 
 init_uart:
 .global early_puts
@@ -404,7 +401,7 @@  early_puts:
 puts:
 putn:   mov   pc, lr
 
-#endif /* EARLY_UART_ADDRESS */
+#endif /* !EARLY_PRINTK */
 
 /*
  * Local variables:
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index be41f43..9484548 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -5,3 +5,5 @@  obj-y += mode_switch.o
 
 obj-y += traps.o
 obj-y += domain.o
+
+obj-$(EARLY_PRINTK) += debug.o
diff --git a/xen/arch/arm/arm64/debug-pl011.inc b/xen/arch/arm/arm64/debug-pl011.inc
new file mode 100644
index 0000000..ee6e0e0
--- /dev/null
+++ b/xen/arch/arm/arm64/debug-pl011.inc
@@ -0,0 +1,59 @@ 
+/*
+ * xen/arch/arm/arm64/debug-pl011.S
+ *
+ * PL011 specific debug code
+ *
+ * Copyright (c) 2013 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/asm_defns.h>
+
+#define EARLY_UART_BASE_ADDRESS 0x1c090000
+
+/* PL011 UART initialization
+ * xb: register which containts the UART base address
+ * c: scratch register number */
+.macro early_uart_init xb, c
+        mov   x\c, #0x0
+        strh  w\c, [\xb, #0x28]      /* -> UARTFBRD (Baud divisor fraction) */
+        mov   x\c, #0x4              /* 7.3728MHz / 0x4 == 16 * 115200 */
+        strh  w\c, [\xb, #0x24]      /* -> UARTIBRD (Baud divisor integer) */
+        mov   x\c, #0x60             /* 8n1 */
+        str   w\c, [\xb, #0x2C]      /* -> UARTLCR_H (Line control) */
+        ldr   x\c, =0x00000301       /* RXE | TXE | UARTEN */
+        str   w\c, [\xb, #0x30]      /* -> UARTCR (Control Register) */
+.endm
+
+/* PL011 UART wait UART to be ready to transmit
+ * xb: register which contains the UART base address
+ * c: scratch register number */
+.macro early_uart_ready xb, c
+1:
+        ldrh  w\c, [\xb, #0x18]      /* <- UARTFR (Flag register) */
+        tst   w\c, #0x8              /* Check BUSY bit */
+        b.ne  1b                     /* Wait for the UART to be ready */
+.endm
+
+/* PL011 UART transmit character
+ * xb: register which contains the UART base address
+ * wt: register which contains the character to transmit */
+.macro early_uart_transmit xb, wt
+        strb  \wt, [\xb]             /* -> UARTDR (Data Register) */
+.endm
+
+/*
+ * Local variables:
+ * mode: ASM
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/arm64/debug.S b/xen/arch/arm/arm64/debug.S
new file mode 100644
index 0000000..48a6567
--- /dev/null
+++ b/xen/arch/arm/arm64/debug.S
@@ -0,0 +1,33 @@ 
+/*
+ * xen/arch/arm/arm64/debug.S
+ *
+ * Wrapper for early printk
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2013 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/config.h>
+
+#ifdef EARLY_PRINTK_INC
+#include EARLY_PRINTK_INC
+#endif
+
+.globl early_putch
+/* Print a character on the UART - this function is called by C
+ * x0: character to print */
+early_putch:
+        ldr   x23, =FIXMAP_ADDR(FIXMAP_CONSOLE)
+        early_uart_ready x23, 1
+        early_uart_transmit x23, w0
+        ret
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index ef02899..79a8da9 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -29,9 +29,13 @@ 
 #define PT_DEV    0xe71 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=0 P=1 */
 #define PT_DEV_L3 0xe73 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=1 P=1 */
 
+#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC))
+#include EARLY_PRINTK_INC
+#endif
+
 /* Macro to print a string to the UART, if there is one.
- * Clobbers r0-r3. */
-#ifdef EARLY_UART_ADDRESS
+ * Clobbers x0-x3. */
+#ifdef EARLY_PRINTK
 #define PRINT(_s)       \
         adr   x0, 98f ; \
         bl    puts    ; \
@@ -39,9 +43,9 @@ 
 98:     .asciz _s     ; \
         .align 2      ; \
 99:
-#else
+#else /* EARLY_PRINTK */
 #define PRINT(s)
-#endif
+#endif /* !EARLY_PRINTK */
 
         /*.aarch64*/
 
@@ -109,8 +113,8 @@  real_start:
 2:
 
 boot_cpu:
-#ifdef EARLY_UART_ADDRESS
-        ldr   x23, =EARLY_UART_ADDRESS  /* x23 := UART base address */
+#ifdef EARLY_PRINTK
+        ldr   x23, =EARLY_UART_BASE_ADDRESS /* x23 := UART base address */
         cbnz  x22, 1f
         bl    init_uart                 /* CPU 0 sets up the UART too */
 1:      PRINT("- CPU ")
@@ -206,7 +210,6 @@  skip_bss:
         mov   x4, x1                 /* Next level into xen_first */
 
        /* console fixmap */
-#ifdef EARLY_UART_ADDRESS
         ldr   x1, =xen_fixmap
         add   x1, x1, x20            /* x1 := paddr (xen_fixmap) */
         lsr   x2, x23, #12
@@ -214,7 +217,6 @@  skip_bss:
         mov   x3, #PT_DEV_L3
         orr   x2, x2, x3             /* x2 := 4K dev map including UART */
         str   x2, [x1, #(FIXMAP_CONSOLE*8)] /* Map it in the first fixmap's slot */
-#endif
 
         /* Build the baseline idle pagetable's first-level entries */
         ldr   x1, =xen_second
@@ -266,10 +268,8 @@  pt_ready:
         br    x1                     /* Get a proper vaddr into PC */
 paging:
 
-#ifdef EARLY_UART_ADDRESS
         /* Use a virtual address to access the UART. */
         ldr   x23, =FIXMAP_ADDR(FIXMAP_CONSOLE)
-#endif
 
         PRINT("- Ready -\r\n")
 
@@ -329,51 +329,44 @@  fail:   PRINT("- Boot failed -\r\n")
 1:      wfe
         b     1b
 
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
 
-/* Bring up the UART. Specific to the PL011 UART.
- * Clobbers r0-r2 */
+/* Bring up the UART.
+ * x23: Early UART base address
+ * Clobbers x0-x1 */
 init_uart:
-        mov   x1, #0x0
-        strh  w1, [x23, #0x24]       /* -> UARTIBRD (Baud divisor fraction) */
-        mov   x1, #0x4               /* 7.3728MHz / 0x4 == 16 * 115200 */
-        strh  w1, [x23, #0x24]       /* -> UARTIBRD (Baud divisor integer) */
-        mov   x1, #0x60              /* 8n1 */
-        strh  w1, [x23, #0x24]       /* -> UARTLCR_H (Line control) */
-        ldr   x1, =0x00000301        /* RXE | TXE | UARTEN */
-        strh  w1, [x23, #0x30]       /* -> UARTCR (Control Register) */
+        early_uart_init x23, 0
         adr   x0, 1f
         b     puts
 1:      .asciz "- UART enabled -\r\n"
         .align 4
 
-/* Print early debug messages.  Specific to the PL011 UART.
- * r0: Nul-terminated string to print.
- * Clobbers r0-r2 */
+/* Print early debug messages.
+ * x0: Nul-terminated string to print.
+ * x23: Early UART base address
+ * Clobbers x0-x1 */
 puts:
-        ldrh  w2, [x23, #0x18]       /* <- UARTFR (Flag register) */
-        tst   w2, #0x8               /* Check BUSY bit */
-        b.ne  puts                   /* Wait for the UART to be ready */
-        ldrb  w2, [x0], #1           /* Load next char */
-        cbz   w2, 1f                 /* Exit on nul */
-        str   w2, [x23]              /* -> UARTDR (Data Register) */
+        early_uart_ready x23, 1
+        ldrb  w1, [x0], #1           /* Load next char */
+        cbz   w1, 1f                 /* Exit on nul */
+        early_uart_transmit x23, w1
         b     puts
 1:
         ret
 
 /* Print a 32-bit number in hex.  Specific to the PL011 UART.
- * r0: Number to print.
- * clobbers r0-r3 */
+ * x0: Number to print.
+ * x23: Early UART base address
+ * Clobbers x0-x3 */
 putn:
         adr   x1, hex
         mov   x3, #8
-1:      ldrh  w2, [x23, #0x18]       /* <- UARTFR (Flag register) */
-        tst   w2, #0x8               /* Check BUSY bit */
-        b.ne  1b                     /* Wait for the UART to be ready */
+1:
+        early_uart_ready x23, 2
         and   x2, x0, #0xf0000000    /* Mask off the top nybble */
         lsr   x2, x2, #28
         ldrb  w2, [x1, x2]           /* Convert to a char */
-        strb  w2, [x23]              /* -> UARTDR (Data Register) */
+        early_uart_transmit x23, w2
         lsl   x0, x0, #4             /* Roll it through one nybble at a time */
         subs  x3, x3, #1
         b.ne  1b
@@ -382,7 +375,7 @@  putn:
 hex:    .ascii "0123456789abcdef"
         .align 2
 
-#else  /* EARLY_UART_ADDRESS */
+#else  /* EARLY_PRINTK */
 
 init_uart:
 .global early_puts
@@ -390,4 +383,4 @@  early_puts:
 puts:
 putn:   ret
 
-#endif /* EARLY_UART_ADDRESS */
+#endif /* EARLY_PRINTK */
diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c
index 65fa912..90ace5d 100644
--- a/xen/arch/arm/early_printk.c
+++ b/xen/arch/arm/early_printk.c
@@ -15,19 +15,7 @@ 
 #include <xen/string.h>
 #include <asm/early_printk.h>
 
-#ifdef EARLY_UART_ADDRESS
-
-void __init early_putch(char c)
-{
-    volatile uint32_t *r;
-
-    r = (uint32_t *)(XEN_VIRT_START + (1 << 21));
-
-    /* XXX: assuming a PL011 UART. */
-    while(*(r + 0x6) & 0x8)
-        ;
-    *r = c;
-}
+void early_putch(char c);
 
 /* Early printk buffer */
 static char __initdata buf[512];
@@ -68,5 +56,3 @@  early_panic(const char *fmt, ...)
 
     while(1);
 }
-
-#endif /* #ifdef EARLY_UART_ADDRESS */
diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h
index 7599202..6414c89 100644
--- a/xen/include/asm-arm/config.h
+++ b/xen/include/asm-arm/config.h
@@ -141,8 +141,6 @@  extern unsigned long frametable_virt_end;
 #define watchdog_disable() ((void)0)
 #define watchdog_enable()  ((void)0)
 
-/* Board-specific: base address of PL011 UART */
-#define EARLY_UART_ADDRESS 0x1c090000
 /* Board-specific: base address of GIC + its regs */
 #define GIC_BASE_ADDRESS 0x2c000000
 #define GIC_DR_OFFSET 0x1000
diff --git a/xen/include/asm-arm/early_printk.h b/xen/include/asm-arm/early_printk.h
index 7083199..c5b99cd 100644
--- a/xen/include/asm-arm/early_printk.h
+++ b/xen/include/asm-arm/early_printk.h
@@ -14,7 +14,7 @@ 
 #include <xen/init.h>
 #include <xen/stdarg.h>
 
-#ifdef EARLY_UART_ADDRESS
+#ifdef EARLY_PRINTK
 
 void __init early_vprintk(const char *fmt, va_list args);
 void early_printk(const char *fmt, ...);