[Xen-devel,2/3,v3] xen: Add support for initializing 16550 UART using ACPI

Message ID 1511523552-23628-3-git-send-email-bhupinder.thakur@linaro.org
State New
Headers show
Series
  • xen: ACPI/SPCR based initialization of 8250 UART
Related show

Commit Message

Bhupinder Thakur Nov. 24, 2017, 11:39 a.m.
Currently, Xen supports only DT based initialization of 16550 UART.
This patch adds support for initializing 16550 UART using ACPI SPCR table.

Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
---
Changes since v2:
- renamed UART_MAX_REG to UART_NUM_REGS
- aligned some assignment statements
- some coding style changes

CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: George Dunlap <George.Dunlap@eu.citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Jan Beulich <jbeulich@suse.com>
CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
CC: Stefano Stabellini <sstabellini@kernel.org>
CC: Tim Deegan <tim@xen.org>
CC: Wei Liu <wei.liu2@citrix.com>
CC: Julien Grall <julien.grall@arm.com>

 xen/drivers/char/ns16550.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/8250-uart.h |  1 +
 2 files changed, 68 insertions(+)

Comments

Konrad Rzeszutek Wilk Nov. 24, 2017, 1:50 p.m. | #1
On Fri, Nov 24, 2017 at 05:09:11PM +0530, Bhupinder Thakur wrote:
> Currently, Xen supports only DT based initialization of 16550 UART.
> This patch adds support for initializing 16550 UART using ACPI SPCR table.

Can you provide the link to the spec you are using. I am wondering
if I am looking at some older one.

> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> Changes since v2:
> - renamed UART_MAX_REG to UART_NUM_REGS
> - aligned some assignment statements
> - some coding style changes
> 
> CC: Andrew Cooper <andrew.cooper3@citrix.com>
> CC: George Dunlap <George.Dunlap@eu.citrix.com>
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> CC: Stefano Stabellini <sstabellini@kernel.org>
> CC: Tim Deegan <tim@xen.org>
> CC: Wei Liu <wei.liu2@citrix.com>
> CC: Julien Grall <julien.grall@arm.com>
> 
>  xen/drivers/char/ns16550.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++
>  xen/include/xen/8250-uart.h |  1 +
>  2 files changed, 68 insertions(+)
> 
> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
> index c5dfc1e..af4712f 100644
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -29,6 +29,10 @@
>  #ifdef CONFIG_X86
>  #include <asm/fixmap.h>
>  #endif
> +#ifdef CONFIG_ACPI
> +#include <xen/acpi.h>
> +#endif
> +
>  
>  /*
>   * Configure serial port with a string:
> @@ -1565,6 +1569,69 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>  DT_DEVICE_END
>  
>  #endif /* HAS_DEVICE_TREE */
> +
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)

I would remove the CONFIG_ARM as the spec says it is possible to use
this on ARM _and_ x86 hardware.

But I guess you can't as ACPI_DEVICE_START is defined to be only
on ARM?

> +
> +static int ns16550_init_acpi(struct ns16550 **puart)
> +{
> +    struct acpi_table_spcr *spcr;
> +    int status;

hmm, not acpi_status ?
> +    struct ns16550 *uart = &ns16550_com[0];
> +
> +    ns16550_init_common(uart);

I would move this below the error check below..
> +
> +    status = acpi_get_table(ACPI_SIG_SPCR, 0,
> +                            (struct acpi_table_header **)&spcr);
> +
> +    if ( ACPI_FAILURE(status) )
> +    {
> +        printk("ns16550: Failed to get SPCR table\n");
> +        return -EINVAL;
> +    }
> +
> +    uart->baud      = BAUD_AUTO;
> +    uart->data_bits = 8;

Are those two assumed from the ACPI spec?

Wait a minute. The
https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx

has Baud Rate at Offset 58?

> +    uart->parity    = spcr->parity;
> +    uart->stop_bits = spcr->stop_bits;
> +    uart->io_base   = spcr->serial_port.address;
> +    uart->irq       = spcr->interrupt;

You need to check if the 'Interrupt Type' field is set before
you look at this?

> +    uart->reg_width = spcr->serial_port.bit_width / 8;
> +    uart->reg_shift = 0;
> +    uart->io_size   = UART_NUM_REGS << uart->reg_shift;
> +
> +    irq_set_type(spcr->interrupt, spcr->interrupt_type);

Um, the spec has a whole bunch of other bits set in 'interrupt_type'?

> +
> +    *puart = uart;
> +
> +    return 0;
> +}
> +
> +static int __init ns16550_acpi_uart_init(const void *data)
> +{
> +    int ret;
> +    struct ns16550 *uart;
> +
> +    ret = ns16550_init_acpi(&uart);
> +    if ( ret )
> +        return ret;
> +
> +    ns16550_vuart_init(uart);
> +
> +    ns16550_register_uart(uart);
> +
> +    return 0;
> +}
> +
> +ACPI_DEVICE_START(ns16550c, "16550 COMPAT UART", DEVICE_SERIAL)
> +        .class_type = ACPI_DBG2_16550_COMPATIBLE,
> +        .init = ns16550_acpi_uart_init,
> +ACPI_DEVICE_END
> +ACPI_DEVICE_START(ns16550s, "16550 SUBSET UART", DEVICE_SERIAL)
> +        .class_type = ACPI_DBG2_16550_SUBSET,
> +        .init = ns16550_acpi_uart_init,
> +ACPI_DEVICE_END
> +
> +#endif
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/include/xen/8250-uart.h b/xen/include/xen/8250-uart.h
> index 5c3bac3..849a5c0 100644
> --- a/xen/include/xen/8250-uart.h
> +++ b/xen/include/xen/8250-uart.h
> @@ -35,6 +35,7 @@
>  #define UART_USR          0x1f    /* Status register (DW) */
>  #define UART_DLL          0x00    /* divisor latch (ls) (DLAB=1) */
>  #define UART_DLM          0x01    /* divisor latch (ms) (DLAB=1) */
> +#define UART_NUM_REGS     (UART_USR + 1)
>  
>  /* Interrupt Enable Register */
>  #define UART_IER_ERDAI    0x01    /* rx data recv'd       */
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xenproject.org
> https://lists.xenproject.org/mailman/listinfo/xen-devel
Andre Przywara Nov. 24, 2017, 3:11 p.m. | #2
Hi,

(answering to both Konrad and Bhupinder ...)

On 24/11/17 13:50, Konrad Rzeszutek Wilk wrote:
> On Fri, Nov 24, 2017 at 05:09:11PM +0530, Bhupinder Thakur wrote:
>> Currently, Xen supports only DT based initialization of 16550 UART.
>> This patch adds support for initializing 16550 UART using ACPI SPCR table.
> 
> Can you provide the link to the spec you are using. I am wondering
> if I am looking at some older one.
> 
>>
>> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
>> ---
>> Changes since v2:
>> - renamed UART_MAX_REG to UART_NUM_REGS
>> - aligned some assignment statements
>> - some coding style changes
>>
>> CC: Andrew Cooper <andrew.cooper3@citrix.com>
>> CC: George Dunlap <George.Dunlap@eu.citrix.com>
>> CC: Ian Jackson <ian.jackson@eu.citrix.com>
>> CC: Jan Beulich <jbeulich@suse.com>
>> CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
>> CC: Stefano Stabellini <sstabellini@kernel.org>
>> CC: Tim Deegan <tim@xen.org>
>> CC: Wei Liu <wei.liu2@citrix.com>
>> CC: Julien Grall <julien.grall@arm.com>
>>
>>  xen/drivers/char/ns16550.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++
>>  xen/include/xen/8250-uart.h |  1 +
>>  2 files changed, 68 insertions(+)
>>
>> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
>> index c5dfc1e..af4712f 100644
>> --- a/xen/drivers/char/ns16550.c
>> +++ b/xen/drivers/char/ns16550.c
>> @@ -29,6 +29,10 @@
>>  #ifdef CONFIG_X86
>>  #include <asm/fixmap.h>
>>  #endif
>> +#ifdef CONFIG_ACPI
>> +#include <xen/acpi.h>
>> +#endif
>> +
>>  
>>  /*
>>   * Configure serial port with a string:
>> @@ -1565,6 +1569,69 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>>  DT_DEVICE_END
>>  
>>  #endif /* HAS_DEVICE_TREE */
>> +
>> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
> 
> I would remove the CONFIG_ARM as the spec says it is possible to use
> this on ARM _and_ x86 hardware.

I was thinking the same. Originally the SPCR was x86 only.

> But I guess you can't as ACPI_DEVICE_START is defined to be only
> on ARM?

We could move the #ifdef there.

>> +
>> +static int ns16550_init_acpi(struct ns16550 **puart)
>> +{
>> +    struct acpi_table_spcr *spcr;
>> +    int status;
> 
> hmm, not acpi_status ?
>> +    struct ns16550 *uart = &ns16550_com[0];
>> +
>> +    ns16550_init_common(uart);
> 
> I would move this below the error check below..
>> +
>> +    status = acpi_get_table(ACPI_SIG_SPCR, 0,
>> +                            (struct acpi_table_header **)&spcr);
>> +
>> +    if ( ACPI_FAILURE(status) )
>> +    {
>> +        printk("ns16550: Failed to get SPCR table\n");
>> +        return -EINVAL;
>> +    }
>> +
>> +    uart->baud      = BAUD_AUTO;
>> +    uart->data_bits = 8;
> 
> Are those two assumed from the ACPI spec?

I can't find a field for the number of data bits, so I assume it's
indeed fixed to 8.

> Wait a minute. The
> https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
> has Baud Rate at Offset 58?

Yes, I see the same. We should use that table.
Just wondering what the Moonshot gives you in this table? Is it "7"?

>> +    uart->parity    = spcr->parity;

The Spec is a bit weird there, since it only specifies 0 as "No parity",
every other value is reserved.
Shall we check and bail out if !0 with an error message?

>> +    uart->stop_bits = spcr->stop_bits;

Again if you want to be strict you would need to check against the
specified values, which means only "1" is valid.

>> +    uart->io_base   = spcr->serial_port.address;

I think this needs to be checked against the address type, because we
assume 0 (MMIO) here for ARM, and I guess 1 (PIO) for x86?

If I understand the code correctly, we have some wild heuristics to
guess the address type at the moment?

#ifdef CONFIG_HAS_IOPORTS
    /* I/O ports are distinguished by their size (16 bits). */
    if ( uart->io_base >= 0x10000 )
#endif

I wonder if we should store this explicitly, since ACPI (and DT as well)
give us this information.

>> +    uart->irq       = spcr->interrupt;
> 
> You need to check if the 'Interrupt Type' field is set before
> you look at this?
> 
>> +    uart->reg_width = spcr->serial_port.bit_width / 8;

I am a bit confused about the SPCR field here. Shouldn't this be encoded
in the "Access Size" field instead?
"Register Bit Width: The size in bits of the given register. When
addressing a data structure, this field must be zero."
But I guess the Moonshot gives you 4 in here, but something else in
"Access Size"?

Cheers,
Andre.

>> +    uart->reg_shift = 0;
>> +    uart->io_size   = UART_NUM_REGS << uart->reg_shift;
>> +
>> +    irq_set_type(spcr->interrupt, spcr->interrupt_type);
> 
> Um, the spec has a whole bunch of other bits set in 'interrupt_type'?
> 
>> +
>> +    *puart = uart;
>> +
>> +    return 0;
>> +}
>> +
>> +static int __init ns16550_acpi_uart_init(const void *data)
>> +{
>> +    int ret;
>> +    struct ns16550 *uart;
>> +
>> +    ret = ns16550_init_acpi(&uart);
>> +    if ( ret )
>> +        return ret;
>> +
>> +    ns16550_vuart_init(uart);
>> +
>> +    ns16550_register_uart(uart);
>> +
>> +    return 0;
>> +}
>> +
>> +ACPI_DEVICE_START(ns16550c, "16550 COMPAT UART", DEVICE_SERIAL)
>> +        .class_type = ACPI_DBG2_16550_COMPATIBLE,
>> +        .init = ns16550_acpi_uart_init,
>> +ACPI_DEVICE_END
>> +ACPI_DEVICE_START(ns16550s, "16550 SUBSET UART", DEVICE_SERIAL)
>> +        .class_type = ACPI_DBG2_16550_SUBSET,
>> +        .init = ns16550_acpi_uart_init,
>> +ACPI_DEVICE_END
>> +
>> +#endif
>>  /*
>>   * Local variables:
>>   * mode: C
>> diff --git a/xen/include/xen/8250-uart.h b/xen/include/xen/8250-uart.h
>> index 5c3bac3..849a5c0 100644
>> --- a/xen/include/xen/8250-uart.h
>> +++ b/xen/include/xen/8250-uart.h
>> @@ -35,6 +35,7 @@
>>  #define UART_USR          0x1f    /* Status register (DW) */
>>  #define UART_DLL          0x00    /* divisor latch (ls) (DLAB=1) */
>>  #define UART_DLM          0x01    /* divisor latch (ms) (DLAB=1) */
>> +#define UART_NUM_REGS     (UART_USR + 1)
>>  
>>  /* Interrupt Enable Register */
>>  #define UART_IER_ERDAI    0x01    /* rx data recv'd       */
>> -- 
>> 2.7.4
>>
>>
Julien Grall Nov. 24, 2017, 3:52 p.m. | #3
Hi,

On 24/11/17 15:11, Andre Przywara wrote:
> On 24/11/17 13:50, Konrad Rzeszutek Wilk wrote:
>> On Fri, Nov 24, 2017 at 05:09:11PM +0530, Bhupinder Thakur wrote:
>>> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
>>> index c5dfc1e..af4712f 100644
>>> --- a/xen/drivers/char/ns16550.c
>>> +++ b/xen/drivers/char/ns16550.c
>>> @@ -29,6 +29,10 @@
>>>   #ifdef CONFIG_X86
>>>   #include <asm/fixmap.h>
>>>   #endif
>>> +#ifdef CONFIG_ACPI
>>> +#include <xen/acpi.h>
>>> +#endif
>>> +
>>>   
>>>   /*
>>>    * Configure serial port with a string:
>>> @@ -1565,6 +1569,69 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>>>   DT_DEVICE_END
>>>   
>>>   #endif /* HAS_DEVICE_TREE */
>>> +
>>> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
>>
>> I would remove the CONFIG_ARM as the spec says it is possible to use
>> this on ARM _and_ x86 hardware.
> 
> I was thinking the same. Originally the SPCR was x86 only.

Yes but Xen does not use SPCR on x86 today. So this will likely lead to 
a build failure as the function would not be used.

Unless someone decided to plug it for x86, the right solution is to 
ifdef CONFIG_ARM that code.

> 
>> But I guess you can't as ACPI_DEVICE_START is defined to be only
>> on ARM?
> 
> We could move the #ifdef there.
> 
>>> +
>>> +static int ns16550_init_acpi(struct ns16550 **puart)
>>> +{
>>> +    struct acpi_table_spcr *spcr;
>>> +    int status;
>>
>> hmm, not acpi_status ?
>>> +    struct ns16550 *uart = &ns16550_com[0];
>>> +
>>> +    ns16550_init_common(uart);
>>
>> I would move this below the error check below..
>>> +
>>> +    status = acpi_get_table(ACPI_SIG_SPCR, 0,
>>> +                            (struct acpi_table_header **)&spcr);
>>> +
>>> +    if ( ACPI_FAILURE(status) )
>>> +    {
>>> +        printk("ns16550: Failed to get SPCR table\n");
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    uart->baud      = BAUD_AUTO;
>>> +    uart->data_bits = 8;
>>
>> Are those two assumed from the ACPI spec?
> 
> I can't find a field for the number of data bits, so I assume it's
> indeed fixed to 8.
> 
>> Wait a minute. The
>> https://msdn.microsoft.com/en-us/library/windows/hardware/dn639132(v=vs.85).aspx
>> has Baud Rate at Offset 58?
> 
> Yes, I see the same. We should use that table.
> Just wondering what the Moonshot gives you in this table? Is it "7"?

What is the point to use the baud rate from the table? It should have 
been configured by the firmware and there are no point for the driver to 
reconfigure it. It will likely make it worst as AFAICT we don't have the 
clock frequency in hand.

Cheers,
Julien Grall Nov. 24, 2017, 4:05 p.m. | #4
Hi Bhupinder,

On 24/11/17 11:39, Bhupinder Thakur wrote:
> Currently, Xen supports only DT based initialization of 16550 UART.
> This patch adds support for initializing 16550 UART using ACPI SPCR table.
> 
> Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org>
> ---
> Changes since v2:
> - renamed UART_MAX_REG to UART_NUM_REGS
> - aligned some assignment statements
> - some coding style changes
> 
> CC: Andrew Cooper <andrew.cooper3@citrix.com>
> CC: George Dunlap <George.Dunlap@eu.citrix.com>
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Jan Beulich <jbeulich@suse.com>
> CC: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> CC: Stefano Stabellini <sstabellini@kernel.org>
> CC: Tim Deegan <tim@xen.org>
> CC: Wei Liu <wei.liu2@citrix.com>
> CC: Julien Grall <julien.grall@arm.com>
> 
>   xen/drivers/char/ns16550.c  | 67 +++++++++++++++++++++++++++++++++++++++++++++
>   xen/include/xen/8250-uart.h |  1 +
>   2 files changed, 68 insertions(+)
> 
> diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
> index c5dfc1e..af4712f 100644
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -29,6 +29,10 @@
>   #ifdef CONFIG_X86
>   #include <asm/fixmap.h>
>   #endif
> +#ifdef CONFIG_ACPI
> +#include <xen/acpi.h>
> +#endif
> +
>   
>   /*
>    * Configure serial port with a string:
> @@ -1565,6 +1569,69 @@ DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
>   DT_DEVICE_END
>   
>   #endif /* HAS_DEVICE_TREE */
> +
> +#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
> +
> +static int ns16550_init_acpi(struct ns16550 **puart)

This should be __init. But why do you need to create 2 separate 
functions? I don't think this bring any enhancement to the code.

> +{
> +    struct acpi_table_spcr *spcr;
> +    int status;
> +    struct ns16550 *uart = &ns16550_com[0];
> +
> +    ns16550_init_common(uart);
> +
> +    status = acpi_get_table(ACPI_SIG_SPCR, 0,
> +                            (struct acpi_table_header **)&spcr);
> +
> +    if ( ACPI_FAILURE(status) )
> +    {
> +        printk("ns16550: Failed to get SPCR table\n");
> +        return -EINVAL;
> +    }
> +
> +    uart->baud      = BAUD_AUTO;
> +    uart->data_bits = 8;
> +    uart->parity    = spcr->parity;
> +    uart->stop_bits = spcr->stop_bits;
> +    uart->io_base   = spcr->serial_port.address;
> +    uart->irq       = spcr->interrupt;
> +    uart->reg_width = spcr->serial_port.bit_width / 8;
> +    uart->reg_shift = 0;
> +    uart->io_size   = UART_NUM_REGS << uart->reg_shift;
> +
> +    irq_set_type(spcr->interrupt, spcr->interrupt_type);
> +
> +    *puart = uart;
> +
> +    return 0;
> +}
> +
> +static int __init ns16550_acpi_uart_init(const void *data)
> +{
> +    int ret;
> +    struct ns16550 *uart;
> +
> +    ret = ns16550_init_acpi(&uart);
> +    if ( ret )
> +        return ret;
> +
> +    ns16550_vuart_init(uart);
> +
> +    ns16550_register_uart(uart);
> +
> +    return 0;
> +}
> +
> +ACPI_DEVICE_START(ns16550c, "16550 COMPAT UART", DEVICE_SERIAL)
> +        .class_type = ACPI_DBG2_16550_COMPATIBLE,
> +        .init = ns16550_acpi_uart_init,
> +ACPI_DEVICE_END
> +ACPI_DEVICE_START(ns16550s, "16550 SUBSET UART", DEVICE_SERIAL)
> +        .class_type = ACPI_DBG2_16550_SUBSET,
> +        .init = ns16550_acpi_uart_init,
> +ACPI_DEVICE_END
> +
> +#endif
>   /*
>    * Local variables:
>    * mode: C
> diff --git a/xen/include/xen/8250-uart.h b/xen/include/xen/8250-uart.h
> index 5c3bac3..849a5c0 100644
> --- a/xen/include/xen/8250-uart.h
> +++ b/xen/include/xen/8250-uart.h
> @@ -35,6 +35,7 @@
>   #define UART_USR          0x1f    /* Status register (DW) */
>   #define UART_DLL          0x00    /* divisor latch (ls) (DLAB=1) */
>   #define UART_DLM          0x01    /* divisor latch (ms) (DLAB=1) */
> +#define UART_NUM_REGS     (UART_USR + 1)
>   
>   /* Interrupt Enable Register */
>   #define UART_IER_ERDAI    0x01    /* rx data recv'd       */
> 

Cheers,
Jan Beulich Nov. 27, 2017, 10:01 a.m. | #5
>>> On 24.11.17 at 12:39, <bhupinder.thakur@linaro.org> wrote:
> --- a/xen/drivers/char/ns16550.c
> +++ b/xen/drivers/char/ns16550.c
> @@ -29,6 +29,10 @@
>  #ifdef CONFIG_X86
>  #include <asm/fixmap.h>
>  #endif
> +#ifdef CONFIG_ACPI
> +#include <xen/acpi.h>
> +#endif
> +
>  
>  /*

No double blank lines please.

Jan

Patch

diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index c5dfc1e..af4712f 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -29,6 +29,10 @@ 
 #ifdef CONFIG_X86
 #include <asm/fixmap.h>
 #endif
+#ifdef CONFIG_ACPI
+#include <xen/acpi.h>
+#endif
+
 
 /*
  * Configure serial port with a string:
@@ -1565,6 +1569,69 @@  DT_DEVICE_START(ns16550, "NS16550 UART", DEVICE_SERIAL)
 DT_DEVICE_END
 
 #endif /* HAS_DEVICE_TREE */
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_ARM)
+
+static int ns16550_init_acpi(struct ns16550 **puart)
+{
+    struct acpi_table_spcr *spcr;
+    int status;
+    struct ns16550 *uart = &ns16550_com[0];
+
+    ns16550_init_common(uart);
+
+    status = acpi_get_table(ACPI_SIG_SPCR, 0,
+                            (struct acpi_table_header **)&spcr);
+
+    if ( ACPI_FAILURE(status) )
+    {
+        printk("ns16550: Failed to get SPCR table\n");
+        return -EINVAL;
+    }
+
+    uart->baud      = BAUD_AUTO;
+    uart->data_bits = 8;
+    uart->parity    = spcr->parity;
+    uart->stop_bits = spcr->stop_bits;
+    uart->io_base   = spcr->serial_port.address;
+    uart->irq       = spcr->interrupt;
+    uart->reg_width = spcr->serial_port.bit_width / 8;
+    uart->reg_shift = 0;
+    uart->io_size   = UART_NUM_REGS << uart->reg_shift;
+
+    irq_set_type(spcr->interrupt, spcr->interrupt_type);
+
+    *puart = uart;
+
+    return 0;
+}
+
+static int __init ns16550_acpi_uart_init(const void *data)
+{
+    int ret;
+    struct ns16550 *uart;
+
+    ret = ns16550_init_acpi(&uart);
+    if ( ret )
+        return ret;
+
+    ns16550_vuart_init(uart);
+
+    ns16550_register_uart(uart);
+
+    return 0;
+}
+
+ACPI_DEVICE_START(ns16550c, "16550 COMPAT UART", DEVICE_SERIAL)
+        .class_type = ACPI_DBG2_16550_COMPATIBLE,
+        .init = ns16550_acpi_uart_init,
+ACPI_DEVICE_END
+ACPI_DEVICE_START(ns16550s, "16550 SUBSET UART", DEVICE_SERIAL)
+        .class_type = ACPI_DBG2_16550_SUBSET,
+        .init = ns16550_acpi_uart_init,
+ACPI_DEVICE_END
+
+#endif
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/xen/8250-uart.h b/xen/include/xen/8250-uart.h
index 5c3bac3..849a5c0 100644
--- a/xen/include/xen/8250-uart.h
+++ b/xen/include/xen/8250-uart.h
@@ -35,6 +35,7 @@ 
 #define UART_USR          0x1f    /* Status register (DW) */
 #define UART_DLL          0x00    /* divisor latch (ls) (DLAB=1) */
 #define UART_DLM          0x01    /* divisor latch (ms) (DLAB=1) */
+#define UART_NUM_REGS     (UART_USR + 1)
 
 /* Interrupt Enable Register */
 #define UART_IER_ERDAI    0x01    /* rx data recv'd       */