From: Michael Brown Date: Mon, 23 Jun 2025 21:40:04 +0000 (+0100) Subject: [dwuart] Read input clock frequency from the device tree X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9ada09c91966c42b49393307b326ff9b078ed448;p=thirdparty%2Fipxe.git [dwuart] Read input clock frequency from the device tree The 16550 design includes a programmable 16-bit clock divider for an arbitrary input clock, requiring knowledge of the input clock frequency in order to calculate the divider value for a given baud rate. The 16550 UARTs in an x86 PC will always have a 1.8432 MHz input clock. Non-x86 systems may have other input clock frequencies. Define the input clock frequency as a property of a 16550 UART, and read the value from the device tree "clock-frequency" property. Signed-off-by: Michael Brown --- diff --git a/src/arch/x86/core/x86_uart.c b/src/arch/x86/core/x86_uart.c index a1d643a58..03809ff9b 100644 --- a/src/arch/x86/core/x86_uart.c +++ b/src/arch/x86/core/x86_uart.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ISA_UART( NAME, BASE ) \ static struct ns16550_uart ns16550_ ## NAME = { \ .base = ( ( void * ) (BASE) ), \ + .clock = NS16550_CLK_DEFAULT, \ }; \ struct uart NAME = { \ .refcnt = REF_INIT ( ref_no_free ), \ diff --git a/src/drivers/uart/dwuart.c b/src/drivers/uart/dwuart.c index 540cde057..ce08e8ebf 100644 --- a/src/drivers/uart/dwuart.c +++ b/src/drivers/uart/dwuart.c @@ -46,6 +46,7 @@ static int dwuart_probe ( struct dt_device *dt, unsigned int offset ) { struct ns16550_uart *ns16550; struct uart *uart; uint32_t shift; + uint32_t clock; int rc; /* Allocate and initialise UART */ @@ -71,6 +72,13 @@ static int dwuart_probe ( struct dt_device *dt, unsigned int offset ) { shift = 0; ns16550->shift = shift; + /* Get clock rate */ + if ( ( rc = fdt_u32 ( &sysfdt, offset, "clock-frequency", + &clock ) ) != 0 ) { + clock = NS16550_CLK_DEFAULT; + } + ns16550->clock = clock; + /* Register UART */ if ( ( rc = uart_register ( uart ) ) != 0 ) goto err_register; diff --git a/src/drivers/uart/ns16550.c b/src/drivers/uart/ns16550.c index 5455c68fb..428771ab5 100644 --- a/src/drivers/uart/ns16550.c +++ b/src/drivers/uart/ns16550.c @@ -138,7 +138,8 @@ static int ns16550_init ( struct uart *uart, unsigned int baud ) { ns16550_write ( ns16550, NS16550_LCR, ( NS16550_LCR_8N1 | NS16550_LCR_DLAB ) ); if ( baud ) { - ns16550->divisor = ( NS16550_MAX_BAUD / baud ); + ns16550->divisor = ( ( ns16550->clock / baud ) / + NS16550_CLK_BIT ); dlm = ( ( ns16550->divisor >> 8 ) & 0xff ); dll = ( ( ns16550->divisor >> 0 ) & 0xff ); ns16550_write ( ns16550, NS16550_DLM, dlm ); diff --git a/src/include/ipxe/ns16550.h b/src/include/ipxe/ns16550.h index 6699205e2..693094866 100644 --- a/src/include/ipxe/ns16550.h +++ b/src/include/ipxe/ns16550.h @@ -73,19 +73,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Divisor latch (most significant byte) */ #define NS16550_DLM 0x01 -/** Maximum baud rate */ -#define NS16550_MAX_BAUD 115200 - /** A 16550-compatible UART */ struct ns16550_uart { /** Register base address */ void *base; /** Register shift */ unsigned int shift; + /** Input clock frequency */ + unsigned int clock; /** Baud rate divisor */ uint16_t divisor; }; +/** Post-division clock cycles per data bit */ +#define NS16550_CLK_BIT 16 + +/** Default input clock rate (1.8432 MHz) */ +#define NS16550_CLK_DEFAULT 1843200 + #include /** Dummy COM1 UART for non-x86 platforms