git: 28ce46d8625d - main - uart/pl011: Add support for computing rclk

From: Warner Losh <imp_at_FreeBSD.org>
Date: Tue, 15 Oct 2024 11:01:16 UTC
The branch main has been updated by imp:

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

commit 28ce46d8625d127a60dd4bb4fb721e5cbbd4096c
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2024-10-15 10:58:49 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-10-15 10:58:49 +0000

    uart/pl011: 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/D47077
---
 sys/dev/uart/uart_dev_pl011.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c
index daba9d19704c..4f946f7c5f36 100644
--- a/sys/dev/uart/uart_dev_pl011.c
+++ b/sys/dev/uart/uart_dev_pl011.c
@@ -231,6 +231,24 @@ uart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
 	__uart_setreg(bas, UART_IFLS, FIFO_IFLS_BITS);
 
 	__uart_setreg(bas, UART_CR, ctrl);
+
+	/*
+	 * Loader tells us to infer the rclk when it sets xo to 0 in
+	 * hw.uart.console. The APCI SPCR code does likewise. 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. This method should be
+	 * good to 5% or better because the error in baud rates needs to be
+	 * below this for devices to communicate.
+	 */
+	if (bas->rclk == 0 && baudrate > 0 && bas->rclk_guess) {
+		uint32_t div;
+
+		div = ((__uart_getreg(bas, UART_IBRD) & IBRD_BDIVINT) << 6) |
+		    (__uart_getreg(bas, UART_FBRD) & FBRD_BDIVFRAC);
+		bas->rclk = (div * baudrate) / 4;
+	}
+
 }
 
 static void