diff mbox series

[11/12] aspeed: Introduce a "uart" machine option

Message ID 20230508075859.3326566-12-clg@kaod.org
State New
Headers show
Series aspeed: fixes and extensions | expand

Commit Message

Cédric Le Goater May 8, 2023, 7:58 a.m. UTC
Most of the Aspeed machines use the UART5 device for the boot console,
and QEMU connects the first serial Chardev to this SoC device for this
purpose. See routine connect_serial_hds_to_uarts().

Nevertheless, some machines use another boot console, such as the fuji,
and commit 5d63d0c76c ("hw/arm/aspeed: Allow machine to set UART
default") introduced a SoC class attribute 'uart_default' and property
to be able to change the boot console device. It was later changed by
commit d2b3eaefb4 ("aspeed: Refactor UART init for multi-SoC machines").

The "uart" machine option goes a step further and lets the user define
the UART device from the QEMU command line without introducing a new
machine definition. For instance, to use device UART3 (mapped on
/dev/ttyS2 under Linux) instead of the default UART5, one would use :

  -M ast2500-evb,uart=uart3

Cc: Abhishek Singh Dagur <abhishek@drut.io>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 docs/system/arm/aspeed.rst | 10 ++++++++++
 hw/arm/aspeed.c            | 39 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 47 insertions(+), 2 deletions(-)

Comments

Philippe Mathieu-Daudé May 30, 2023, 9:22 p.m. UTC | #1
On 8/5/23 09:58, Cédric Le Goater wrote:
> Most of the Aspeed machines use the UART5 device for the boot console,
> and QEMU connects the first serial Chardev to this SoC device for this
> purpose. See routine connect_serial_hds_to_uarts().
> 
> Nevertheless, some machines use another boot console, such as the fuji,
> and commit 5d63d0c76c ("hw/arm/aspeed: Allow machine to set UART
> default") introduced a SoC class attribute 'uart_default' and property
> to be able to change the boot console device. It was later changed by
> commit d2b3eaefb4 ("aspeed: Refactor UART init for multi-SoC machines").
> 
> The "uart" machine option goes a step further and lets the user define
> the UART device from the QEMU command line without introducing a new
> machine definition. For instance, to use device UART3 (mapped on
> /dev/ttyS2 under Linux) instead of the default UART5, one would use :
> 
>    -M ast2500-evb,uart=uart3
> 
> Cc: Abhishek Singh Dagur <abhishek@drut.io>
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
>   docs/system/arm/aspeed.rst | 10 ++++++++++
>   hw/arm/aspeed.c            | 39 ++++++++++++++++++++++++++++++++++++--
>   2 files changed, 47 insertions(+), 2 deletions(-)
> 
> diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
> index d4e293e7f9..e70f0aeea3 100644
> --- a/docs/system/arm/aspeed.rst
> +++ b/docs/system/arm/aspeed.rst
> @@ -122,6 +122,10 @@ Options specific to Aspeed machines are :
>   
>    * ``spi-model`` to change the SPI Flash model.
>   
> + * ``uart`` to change the default console device. Most of the machines
> +   use the ``UART5`` device for a boot console, which is mapped on
> +   ``/dev/ttyS4`` under Linux, but it is not always the case.

This comment ...

>   For instance, to start the ``ast2500-evb`` machine with a different
>   FMC chip and a bigger (64M) SPI chip, use :
>   
> @@ -129,6 +133,12 @@ FMC chip and a bigger (64M) SPI chip, use :
>   
>     -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f
>   
> +To change the boot console and use device ``UART3`` (``/dev/ttyS2``
> +under Linux), use :

... and this one suggest 'boot-console' could be a better name.

Or 'boot-console-index'.

> +.. code-block:: bash
> +
> +  -M ast2500-evb,uart=uart3
>   
>   Aspeed minibmc family boards (``ast1030-evb``)
>   ==================================================================
> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
> index 3d5488faf7..6c32f674b9 100644
> --- a/hw/arm/aspeed.c
> +++ b/hw/arm/aspeed.c
> @@ -43,6 +43,7 @@ struct AspeedMachineState {
>       AspeedSoCState soc;
>       MemoryRegion boot_rom;
>       bool mmio_exec;
> +    uint32_t uart_chosen;
>       char *fmc_model;
>       char *spi_model;
>   };
> @@ -331,10 +332,11 @@ static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
>       AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>       AspeedSoCState *s = &bmc->soc;
>       AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
>   
> -    aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
> +    aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0));
>       for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
> -        if (uart == amc->uart_default) {
> +        if (uart == uart_chosen) {
>               continue;
>           }
>           aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
> @@ -1077,6 +1079,35 @@ static void aspeed_set_spi_model(Object *obj, const char *value, Error **errp)
>       bmc->spi_model = g_strdup(value);
>   }
>   
> +static char *aspeed_get_uart(Object *obj, Error **errp)
> +{
> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
> +
> +    return g_strdup_printf("uart%d", uart_chosen - ASPEED_DEV_UART1 + 1);
> +}
> +
> +static void aspeed_set_uart(Object *obj, const char *value, Error **errp)
> +{
> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
> +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name));
> +    int val;
> +
> +    if (sscanf(value, "uart%u", &val) != 1) {
> +        error_setg(errp, "Bad value for \"uart\" property");

Why are you asking for a string and not an index?

> +        return;
> +    }
> +
> +    /* The number of UART depends on the SoC */
> +    if (val < 1 || val > sc->uarts_num) {
> +        error_setg(errp, "\"uart\" should be in range [1 - %d]", sc->uarts_num);
> +        return;
> +    }
> +    bmc->uart_chosen = ASPEED_DEV_UART1 + val - 1;
> +}
> +
>   static void aspeed_machine_class_props_init(ObjectClass *oc)
>   {
>       object_class_property_add_bool(oc, "execute-in-place",
> @@ -1085,6 +1116,10 @@ static void aspeed_machine_class_props_init(ObjectClass *oc)
>       object_class_property_set_description(oc, "execute-in-place",
>                              "boot directly from CE0 flash device");
>   
> +    object_class_property_add_str(oc, "uart", aspeed_get_uart, aspeed_set_uart);
> +    object_class_property_set_description(oc, "uart",
> +                           "Change the default UART to \"uartX\"");
> +
>       object_class_property_add_str(oc, "fmc-model", aspeed_get_fmc_model,
>                                      aspeed_set_fmc_model);
>       object_class_property_set_description(oc, "fmc-model",
Cédric Le Goater May 31, 2023, 6:28 a.m. UTC | #2
On 5/30/23 23:22, Philippe Mathieu-Daudé wrote:
> On 8/5/23 09:58, Cédric Le Goater wrote:
>> Most of the Aspeed machines use the UART5 device for the boot console,
>> and QEMU connects the first serial Chardev to this SoC device for this
>> purpose. See routine connect_serial_hds_to_uarts().
>>
>> Nevertheless, some machines use another boot console, such as the fuji,
>> and commit 5d63d0c76c ("hw/arm/aspeed: Allow machine to set UART
>> default") introduced a SoC class attribute 'uart_default' and property
>> to be able to change the boot console device. It was later changed by
>> commit d2b3eaefb4 ("aspeed: Refactor UART init for multi-SoC machines").
>>
>> The "uart" machine option goes a step further and lets the user define
>> the UART device from the QEMU command line without introducing a new
>> machine definition. For instance, to use device UART3 (mapped on
>> /dev/ttyS2 under Linux) instead of the default UART5, one would use :
>>
>>    -M ast2500-evb,uart=uart3
>>
>> Cc: Abhishek Singh Dagur <abhishek@drut.io>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>   docs/system/arm/aspeed.rst | 10 ++++++++++
>>   hw/arm/aspeed.c            | 39 ++++++++++++++++++++++++++++++++++++--
>>   2 files changed, 47 insertions(+), 2 deletions(-)
>>
>> diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
>> index d4e293e7f9..e70f0aeea3 100644
>> --- a/docs/system/arm/aspeed.rst
>> +++ b/docs/system/arm/aspeed.rst
>> @@ -122,6 +122,10 @@ Options specific to Aspeed machines are :
>>    * ``spi-model`` to change the SPI Flash model.
>> + * ``uart`` to change the default console device. Most of the machines
>> +   use the ``UART5`` device for a boot console, which is mapped on
>> +   ``/dev/ttyS4`` under Linux, but it is not always the case.
> 
> This comment ...
> 
>>   For instance, to start the ``ast2500-evb`` machine with a different
>>   FMC chip and a bigger (64M) SPI chip, use :
>> @@ -129,6 +133,12 @@ FMC chip and a bigger (64M) SPI chip, use :
>>     -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f
>> +To change the boot console and use device ``UART3`` (``/dev/ttyS2``
>> +under Linux), use :
> 
> ... and this one suggest 'boot-console' could be a better name.
> 
> Or 'boot-console-index'.

you might be right. people expect to find the console messages on
this device. I will think about it.

> 
>> +.. code-block:: bash
>> +
>> +  -M ast2500-evb,uart=uart3
>>   Aspeed minibmc family boards (``ast1030-evb``)
>>   ==================================================================
>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
>> index 3d5488faf7..6c32f674b9 100644
>> --- a/hw/arm/aspeed.c
>> +++ b/hw/arm/aspeed.c
>> @@ -43,6 +43,7 @@ struct AspeedMachineState {
>>       AspeedSoCState soc;
>>       MemoryRegion boot_rom;
>>       bool mmio_exec;
>> +    uint32_t uart_chosen;
>>       char *fmc_model;
>>       char *spi_model;
>>   };
>> @@ -331,10 +332,11 @@ static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
>>       AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>>       AspeedSoCState *s = &bmc->soc;
>>       AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
>> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
>> -    aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
>> +    aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0));
>>       for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
>> -        if (uart == amc->uart_default) {
>> +        if (uart == uart_chosen) {
>>               continue;
>>           }
>>           aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
>> @@ -1077,6 +1079,35 @@ static void aspeed_set_spi_model(Object *obj, const char *value, Error **errp)
>>       bmc->spi_model = g_strdup(value);
>>   }
>> +static char *aspeed_get_uart(Object *obj, Error **errp)
>> +{
>> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
>> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
>> +
>> +    return g_strdup_printf("uart%d", uart_chosen - ASPEED_DEV_UART1 + 1);
>> +}
>> +
>> +static void aspeed_set_uart(Object *obj, const char *value, Error **errp)
>> +{
>> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
>> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>> +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name));
>> +    int val;
>> +
>> +    if (sscanf(value, "uart%u", &val) != 1) {
>> +        error_setg(errp, "Bad value for \"uart\" property");
> 
> Why are you asking for a string and not an index?

because the literal name is what people find in the DT. See files
arch/arm/boot/dts/aspeed-bmc-* under Linux.

Thanks,

C.

> 
>> +        return;
>> +    }
>> +
>> +    /* The number of UART depends on the SoC */
>> +    if (val < 1 || val > sc->uarts_num) {
>> +        error_setg(errp, "\"uart\" should be in range [1 - %d]", sc->uarts_num);
>> +        return;
>> +    }
>> +    bmc->uart_chosen = ASPEED_DEV_UART1 + val - 1;
>> +}
>> +
>>   static void aspeed_machine_class_props_init(ObjectClass *oc)
>>   {
>>       object_class_property_add_bool(oc, "execute-in-place",
>> @@ -1085,6 +1116,10 @@ static void aspeed_machine_class_props_init(ObjectClass *oc)
>>       object_class_property_set_description(oc, "execute-in-place",
>>                              "boot directly from CE0 flash device");
>> +    object_class_property_add_str(oc, "uart", aspeed_get_uart, aspeed_set_uart);
>> +    object_class_property_set_description(oc, "uart",
>> +                           "Change the default UART to \"uartX\"");
>> +
>>       object_class_property_add_str(oc, "fmc-model", aspeed_get_fmc_model,
>>                                      aspeed_set_fmc_model);
>>       object_class_property_set_description(oc, "fmc-model",
>
Philippe Mathieu-Daudé May 31, 2023, 7:50 a.m. UTC | #3
On 31/5/23 08:28, Cédric Le Goater wrote:
> On 5/30/23 23:22, Philippe Mathieu-Daudé wrote:
>> On 8/5/23 09:58, Cédric Le Goater wrote:
>>> Most of the Aspeed machines use the UART5 device for the boot console,
>>> and QEMU connects the first serial Chardev to this SoC device for this
>>> purpose. See routine connect_serial_hds_to_uarts().
>>>
>>> Nevertheless, some machines use another boot console, such as the fuji,
>>> and commit 5d63d0c76c ("hw/arm/aspeed: Allow machine to set UART
>>> default") introduced a SoC class attribute 'uart_default' and property
>>> to be able to change the boot console device. It was later changed by
>>> commit d2b3eaefb4 ("aspeed: Refactor UART init for multi-SoC machines").
>>>
>>> The "uart" machine option goes a step further and lets the user define
>>> the UART device from the QEMU command line without introducing a new
>>> machine definition. For instance, to use device UART3 (mapped on
>>> /dev/ttyS2 under Linux) instead of the default UART5, one would use :
>>>
>>>    -M ast2500-evb,uart=uart3
>>>
>>> Cc: Abhishek Singh Dagur <abhishek@drut.io>
>>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>>> ---
>>>   docs/system/arm/aspeed.rst | 10 ++++++++++
>>>   hw/arm/aspeed.c            | 39 ++++++++++++++++++++++++++++++++++++--
>>>   2 files changed, 47 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
>>> index d4e293e7f9..e70f0aeea3 100644
>>> --- a/docs/system/arm/aspeed.rst
>>> +++ b/docs/system/arm/aspeed.rst
>>> @@ -122,6 +122,10 @@ Options specific to Aspeed machines are :
>>>    * ``spi-model`` to change the SPI Flash model.
>>> + * ``uart`` to change the default console device. Most of the machines
>>> +   use the ``UART5`` device for a boot console, which is mapped on
>>> +   ``/dev/ttyS4`` under Linux, but it is not always the case.
>>
>> This comment ...
>>
>>>   For instance, to start the ``ast2500-evb`` machine with a different
>>>   FMC chip and a bigger (64M) SPI chip, use :
>>> @@ -129,6 +133,12 @@ FMC chip and a bigger (64M) SPI chip, use :
>>>     -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f
>>> +To change the boot console and use device ``UART3`` (``/dev/ttyS2``
>>> +under Linux), use :
>>
>> ... and this one suggest 'boot-console' could be a better name.
>>
>> Or 'boot-console-index'.
> 
> you might be right. people expect to find the console messages on
> this device. I will think about it.
> 
>>
>>> +.. code-block:: bash
>>> +
>>> +  -M ast2500-evb,uart=uart3
>>>   Aspeed minibmc family boards (``ast1030-evb``)
>>>   ==================================================================
>>> diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
>>> index 3d5488faf7..6c32f674b9 100644
>>> --- a/hw/arm/aspeed.c
>>> +++ b/hw/arm/aspeed.c
>>> @@ -43,6 +43,7 @@ struct AspeedMachineState {
>>>       AspeedSoCState soc;
>>>       MemoryRegion boot_rom;
>>>       bool mmio_exec;
>>> +    uint32_t uart_chosen;
>>>       char *fmc_model;
>>>       char *spi_model;
>>>   };
>>> @@ -331,10 +332,11 @@ static void 
>>> connect_serial_hds_to_uarts(AspeedMachineState *bmc)
>>>       AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>>>       AspeedSoCState *s = &bmc->soc;
>>>       AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
>>> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : 
>>> amc->uart_default;
>>> -    aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
>>> +    aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0));
>>>       for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; 
>>> i++, uart++) {
>>> -        if (uart == amc->uart_default) {
>>> +        if (uart == uart_chosen) {
>>>               continue;
>>>           }
>>>           aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
>>> @@ -1077,6 +1079,35 @@ static void aspeed_set_spi_model(Object *obj, 
>>> const char *value, Error **errp)
>>>       bmc->spi_model = g_strdup(value);
>>>   }
>>> +static char *aspeed_get_uart(Object *obj, Error **errp)
>>> +{
>>> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
>>> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>>> +    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : 
>>> amc->uart_default;
>>> +
>>> +    return g_strdup_printf("uart%d", uart_chosen - ASPEED_DEV_UART1 
>>> + 1);
>>> +}
>>> +
>>> +static void aspeed_set_uart(Object *obj, const char *value, Error 
>>> **errp)
>>> +{
>>> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
>>> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>>> +    AspeedSoCClass *sc = 
>>> ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name));
>>> +    int val;
>>> +
>>> +    if (sscanf(value, "uart%u", &val) != 1) {
>>> +        error_setg(errp, "Bad value for \"uart\" property");
>>
>> Why are you asking for a string and not an index?
> 
> because the literal name is what people find in the DT. See files
> arch/arm/boot/dts/aspeed-bmc-* under Linux.

OK. After looking at this file, I suppose people would expect
a "bmc-console" property name:

   -M ast2500-evb,bmc-console=uart3
Cédric Le Goater May 31, 2023, 8:47 a.m. UTC | #4
>>>> +static void aspeed_set_uart(Object *obj, const char *value, Error **errp)
>>>> +{
>>>> +    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
>>>> +    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
>>>> +    AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name));
>>>> +    int val;
>>>> +
>>>> +    if (sscanf(value, "uart%u", &val) != 1) {
>>>> +        error_setg(errp, "Bad value for \"uart\" property");
>>>
>>> Why are you asking for a string and not an index?
>>
>> because the literal name is what people find in the DT. See files
>> arch/arm/boot/dts/aspeed-bmc-* under Linux.
> 
> OK. After looking at this file, I suppose people would expect
> a "bmc-console" property name:
> 
>    -M ast2500-evb,bmc-console=uart3
> 

yes. This is better naming for the user. I will keep the internal
'uart_chosen' though.

Thanks,

C.
diff mbox series

Patch

diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst
index d4e293e7f9..e70f0aeea3 100644
--- a/docs/system/arm/aspeed.rst
+++ b/docs/system/arm/aspeed.rst
@@ -122,6 +122,10 @@  Options specific to Aspeed machines are :
 
  * ``spi-model`` to change the SPI Flash model.
 
+ * ``uart`` to change the default console device. Most of the machines
+   use the ``UART5`` device for a boot console, which is mapped on
+   ``/dev/ttyS4`` under Linux, but it is not always the case.
+
 For instance, to start the ``ast2500-evb`` machine with a different
 FMC chip and a bigger (64M) SPI chip, use :
 
@@ -129,6 +133,12 @@  FMC chip and a bigger (64M) SPI chip, use :
 
   -M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f
 
+To change the boot console and use device ``UART3`` (``/dev/ttyS2``
+under Linux), use :
+
+.. code-block:: bash
+
+  -M ast2500-evb,uart=uart3
 
 Aspeed minibmc family boards (``ast1030-evb``)
 ==================================================================
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c
index 3d5488faf7..6c32f674b9 100644
--- a/hw/arm/aspeed.c
+++ b/hw/arm/aspeed.c
@@ -43,6 +43,7 @@  struct AspeedMachineState {
     AspeedSoCState soc;
     MemoryRegion boot_rom;
     bool mmio_exec;
+    uint32_t uart_chosen;
     char *fmc_model;
     char *spi_model;
 };
@@ -331,10 +332,11 @@  static void connect_serial_hds_to_uarts(AspeedMachineState *bmc)
     AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
     AspeedSoCState *s = &bmc->soc;
     AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s);
+    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
 
-    aspeed_soc_uart_set_chr(s, amc->uart_default, serial_hd(0));
+    aspeed_soc_uart_set_chr(s, uart_chosen, serial_hd(0));
     for (int i = 1, uart = ASPEED_DEV_UART1; i < sc->uarts_num; i++, uart++) {
-        if (uart == amc->uart_default) {
+        if (uart == uart_chosen) {
             continue;
         }
         aspeed_soc_uart_set_chr(s, uart, serial_hd(i));
@@ -1077,6 +1079,35 @@  static void aspeed_set_spi_model(Object *obj, const char *value, Error **errp)
     bmc->spi_model = g_strdup(value);
 }
 
+static char *aspeed_get_uart(Object *obj, Error **errp)
+{
+    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
+    int uart_chosen = bmc->uart_chosen ? bmc->uart_chosen : amc->uart_default;
+
+    return g_strdup_printf("uart%d", uart_chosen - ASPEED_DEV_UART1 + 1);
+}
+
+static void aspeed_set_uart(Object *obj, const char *value, Error **errp)
+{
+    AspeedMachineState *bmc = ASPEED_MACHINE(obj);
+    AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(bmc);
+    AspeedSoCClass *sc = ASPEED_SOC_CLASS(object_class_by_name(amc->soc_name));
+    int val;
+
+    if (sscanf(value, "uart%u", &val) != 1) {
+        error_setg(errp, "Bad value for \"uart\" property");
+        return;
+    }
+
+    /* The number of UART depends on the SoC */
+    if (val < 1 || val > sc->uarts_num) {
+        error_setg(errp, "\"uart\" should be in range [1 - %d]", sc->uarts_num);
+        return;
+    }
+    bmc->uart_chosen = ASPEED_DEV_UART1 + val - 1;
+}
+
 static void aspeed_machine_class_props_init(ObjectClass *oc)
 {
     object_class_property_add_bool(oc, "execute-in-place",
@@ -1085,6 +1116,10 @@  static void aspeed_machine_class_props_init(ObjectClass *oc)
     object_class_property_set_description(oc, "execute-in-place",
                            "boot directly from CE0 flash device");
 
+    object_class_property_add_str(oc, "uart", aspeed_get_uart, aspeed_set_uart);
+    object_class_property_set_description(oc, "uart",
+                           "Change the default UART to \"uartX\"");
+
     object_class_property_add_str(oc, "fmc-model", aspeed_get_fmc_model,
                                    aspeed_set_fmc_model);
     object_class_property_set_description(oc, "fmc-model",