riscv_create_fdt_uart() is defaulting to a 3.6864 Mhz clock, which Linux will interpret as a 230400 base baud serial.
We need more flexibility to set a different baud rate for UART devices. Add an optional 'base_baud' parameter that allows callers to set a baud rate for the related device. We're keeping the existing default in case the caller does not care to provide a base baud. Signed-off-by: Daniel Henrique Barboza <[email protected]> --- hw/riscv/fdt-common.c | 19 +++++++++++++++++-- hw/riscv/server_platform_ref.c | 1 + hw/riscv/virt.c | 4 ++-- include/hw/riscv/fdt-common.h | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/hw/riscv/fdt-common.c b/hw/riscv/fdt-common.c index ce2dcb43b4..abb913faec 100644 --- a/hw/riscv/fdt-common.c +++ b/hw/riscv/fdt-common.c @@ -22,7 +22,11 @@ #include "hw/pci/pcie_host.h" #include "hw/riscv/aia.h" -#define UART_STD_CLOCK_FREQ 3686400 /* 3.6864 MHz */ + /* + * This 3.6864 MHz default clock results in a base + * baud of 230400 symbols/second. + */ +#define UART_STD_CLOCK_FREQ 3686400 void *riscv_create_board_device_tree(const char *model, const char *compatible, int *fdt_size) @@ -807,11 +811,14 @@ char *riscv_fdt_get_uart_nodename(hwaddr addr) return g_strdup_printf("/soc/serial@%"HWADDR_PRIx, addr); } +/* If base_baud = 0 this function assumes a base baud of 230400. */ void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem, int uart_irq, int aia_type, + int base_baud, uint32_t irq_phandle) { g_autofree char *name = riscv_fdt_get_uart_nodename(uart_mem->base); + uint64_t clock_freq = UART_STD_CLOCK_FREQ; qemu_fdt_add_subnode(fdt, name); qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a"); @@ -819,7 +826,15 @@ void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem, 2, uart_mem->base, 2, uart_mem->size); - qemu_fdt_setprop_cell(fdt, name, "clock-frequency", UART_STD_CLOCK_FREQ); + if (base_baud != 0) { + /* + * The base baud formula is base_baud = clock_freq / 16, + * ergo clock_freq = base_baud * 16. + */ + clock_freq = base_baud * 16; + } + + qemu_fdt_setprop_cell(fdt, name, "clock-frequency", clock_freq); qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", irq_phandle); if (aia_type == AIA_TYPE_NONE) { diff --git a/hw/riscv/server_platform_ref.c b/hw/riscv/server_platform_ref.c index ea24720a08..3191615c02 100644 --- a/hw/riscv/server_platform_ref.c +++ b/hw/riscv/server_platform_ref.c @@ -315,6 +315,7 @@ static void finalize_fdt(RISCVServerRefMachineState *s) riscv_create_fdt_uart(ms->fdt, &rvserver_ref_memmap[RVSERVER_UART0], RVSERVER_UART0_IRQ, AIA_TYPE_APLIC_IMSIC, + 0, irq_mmio_phandle); name = riscv_fdt_get_uart_nodename(rvserver_ref_memmap[RVSERVER_UART0].base); qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 39381cb21d..c4447d971b 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -385,11 +385,11 @@ static void create_fdt_uarts(RISCVVirtState *s, uint32_t irq_mmio_phandle) if (s->uart1_present) { riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART1], - UART1_IRQ, s->aia_type, irq_mmio_phandle); + UART1_IRQ, 0, s->aia_type, irq_mmio_phandle); } riscv_create_fdt_uart(ms->fdt, &s->memmap[VIRT_UART0], UART0_IRQ, - s->aia_type, irq_mmio_phandle); + s->aia_type, 0, irq_mmio_phandle); name = riscv_fdt_get_uart_nodename(s->memmap[VIRT_UART0].base); qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", name); diff --git a/include/hw/riscv/fdt-common.h b/include/hw/riscv/fdt-common.h index eb9db8278d..ee664983f4 100644 --- a/include/hw/riscv/fdt-common.h +++ b/include/hw/riscv/fdt-common.h @@ -132,6 +132,7 @@ void riscv_create_fdt_socket_aclint(void *fdt, ACLINTFdtProps *props, char *riscv_fdt_get_uart_nodename(hwaddr addr); void riscv_create_fdt_uart(void *fdt, const MemMapEntry *uart_mem, int uart_irq, int aia_type, + int base_baud, uint32_t irq_phandle); void riscv_create_fdt_rtc(void *fdt, const MemMapEntry *rtc_mem, int rtc_irq, int aia_type, -- 2.43.0
