aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2024-10-15 10:58:49 +0000
committerWarner Losh <imp@FreeBSD.org>2024-10-15 10:58:49 +0000
commit28ce46d8625d127a60dd4bb4fb721e5cbbd4096c (patch)
tree903c6e9a20c476b7565314a6cc380ee10b8779cb /sys
parent481d5a4891648f0a6979a48689cc16fca80d4ab6 (diff)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/uart/uart_dev_pl011.c18
1 files changed, 18 insertions, 0 deletions
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