[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 <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2025-06-23 22:40:04 +01:00
parent 0ed1dea7f4
commit 9ada09c919
4 changed files with 19 additions and 4 deletions

View File

@@ -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 ), \

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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 <bits/ns16550.h>
/** Dummy COM1 UART for non-x86 platforms