From the generic 16550 UART initialization code (drivers/ti/uart/aarch64/16550_console.S):
/* ----------------------------------------------- [...] * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate [...] /* Program the baudrate */ /* Divisor = Uart clock / (16 * baudrate) */ lsl w2, w2, #4 udiv w2, w1, w2 and w1, w2, #0xff /* w1 = DLL */ lsr w2, w2, #8 and w2, w2, #0xff /* w2 = DLLM */
I think it would be better if the division result is rounded so that we get a better actual clock rate if the uart clock doesn't divide into the baud rate very well (eg by adding add w1, w1, w2, LSR #1 just before the udiv) . This is what all of Linux, U-Boot and EDK2 do:
- https://github.com/tianocore/edk2/blob/edk2-stable201905/MdeModulePkg/Library/BaseSerialPortLib16550/BaseSerialPortLib16550.c#L504
- https://github.com/u-boot/u-boot/blob/v2019.10-rc1/drivers/serial/ns16550.c#L146
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/tty/serial/serial_core.c?h=v5.3-rc3#n491