git: b2fd259edd18 - main - uart: Add a signal to compute rclk from baudrate

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

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

commit b2fd259edd18af1fe35912bdb602bbe907dbbbcb
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-10-14 21:57:25 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-10-14 22:03:58 +0000

    uart: Add a signal to compute rclk from baudrate
    
    With newer, more diverse hardware designs, the rclk can be
    unknown. Currently deployed systems have no standard way to discover the
    baud-clock generator frequency. However, sometimes we have a fairly good
    idea that the firmware programmed the UART to be the baud rate that it's
    telling us it's at. Create a way to instruct the uart class drivers to
    compute the baud clock frequency the first time their init routines are
    called. Usually the 'divisors' are relatively small, meaning we will
    likely have a fairly large error (goes as 1 / (divisor + 1). However,
    we also know that the baud-generator clock  needs to be divided down
    to the baud-rate +/- about 5% (so while the error could be large for
    an arbitrary baud-clock, standard baud rates generally will give
    an error of 5% or less).
    
    Often, the console speed and the getty-configured speed are the same, so
    this heuristic allows boot messages and login sessions to work.
    
    Sponsored by:           Netflix
    Reviewed by:            andrew
    Differential Revision:  https://reviews.freebsd.org/D47072
---
 sys/dev/uart/uart.h          | 1 +
 sys/dev/uart/uart_cpu_acpi.c | 8 ++++++++
 sys/dev/uart/uart_subr.c     | 2 ++
 3 files changed, 11 insertions(+)

diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h
index 4cdec00c9829..9b80f0148dc2 100644
--- a/sys/dev/uart/uart.h
+++ b/sys/dev/uart/uart.h
@@ -45,6 +45,7 @@ struct uart_bas {
 	u_int	regshft;
 	u_int	regiowidth;
 	u_int	busy_detect;
+	u_int	rclk_guess;/* if rclk == 0, use baud + divisor to compute rclk */
 };
 
 #define	uart_regofs(bas, reg)		((reg) << (bas)->regshft)
diff --git a/sys/dev/uart/uart_cpu_acpi.c b/sys/dev/uart/uart_cpu_acpi.c
index ae22a9822aa6..816738ec31d5 100644
--- a/sys/dev/uart/uart_cpu_acpi.c
+++ b/sys/dev/uart/uart_cpu_acpi.c
@@ -189,6 +189,14 @@ uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di)
 		    (int)spcr->BaudRate);
 		goto out;
 	}
+	/*
+	 * If no rclk is set, then we will assume the BIOS has configured the
+	 * hardware at the stated baudrate, so we can use it to guess the rclk
+	 * relatively accurately, so make a note for later.
+	 */
+	if (di->bas.rclk == 0)
+		di->bas.rclk_guess = 1;
+
 	if (spcr->PciVendorId != PCIV_INVALID &&
 	    spcr->PciDeviceId != PCIV_INVALID) {
 		di->pci_info.vendor = spcr->PciVendorId;
diff --git a/sys/dev/uart/uart_subr.c b/sys/dev/uart/uart_subr.c
index 49a046f019bb..070ae80d9aff 100644
--- a/sys/dev/uart/uart_subr.c
+++ b/sys/dev/uart/uart_subr.c
@@ -279,6 +279,8 @@ uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class)
 			break;
 		case UART_TAG_XO:
 			di->bas.rclk = uart_parse_long(&spec);
+			if (di->bas.rclk == 0)
+				di->bas.rclk_guess = 1;
 			break;
 		default:
 			goto inval;