git: 8190dfbb1d58 - main - uart/ns8250: Add support for computing rclk

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 14 Oct 2024 22:17:38 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=8190dfbb1d58a1c52f73992d84ae00c4fff35890

commit 8190dfbb1d58a1c52f73992d84ae00c4fff35890
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-10-14 21:58:01 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-10-14 22:03:59 +0000

    uart/ns8250: Add support for computing rclk
    
    When instructed to do so, compute the rclk (baud rate generator clock)
    based on the currently programmed divisor and the communicated baud
    rate.  We only do this once and only for consoles that tell us the
    configured rate and flag we can likely safely compute rclk.
    
    Sponsored by:           Netflix
    Reviewed by:            andrew
    Differential Revision:  https://reviews.freebsd.org/D47076
---
 sys/dev/uart/uart_dev_ns8250.c | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index f59f5fa80e9c..3da2e8b8c758 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -294,8 +294,8 @@ ns8250_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
 		lcr |= LCR_STOPB;
 	lcr |= parity << 3;
 
-	/* Set baudrate. */
-	if (baudrate > 0) {
+	/* Set baudrate if we know a rclk and both are not 0. */
+	if (baudrate > 0 && bas->rclk > 0) {
 		divisor = ns8250_divisor(bas->rclk, baudrate);
 		if (divisor == 0)
 			return (EINVAL);
@@ -369,8 +369,28 @@ ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
 	uart_setreg(bas, REG_IER, ier);
 	uart_barrier(bas);
 
-	if (bas->rclk == 0)
+	/*
+	 * Loader tells us to infer the rclk when it sets xo to 0 in
+	 * hw.uart.console. We know the baudrate was set by the firmware, so
+	 * calculate rclk from baudrate and the divisor register.  If 'div' is
+	 * actually 0, the resulting 0 value will have us fall back to other
+	 * rclk methods.
+	 */
+	if (bas->rclk_guess && bas->rclk == 0 && baudrate != 0) {
+		uint32_t div;
+
+		div = ns8250_get_divisor(bas);
+		bas->rclk = baudrate * div * 16;
+	}
+
+	/*
+	 * Pick a default because we just don't know. This likely needs future
+	 * refinement, but that's hard outside of consoles to know what to use.
+	 * But defer as long as possible if there's no defined baud rate.
+	 */
+	if (bas->rclk == 0 && baudrate != 0)
 		bas->rclk = DEFAULT_RCLK;
+
 	ns8250_param(bas, baudrate, databits, stopbits, parity);
 
 	/* Disable the FIFO (if present). */