git: 202890922e31 - main - sys: Simplify enabling EARLY_PRINTF uarts

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Tue, 13 Feb 2024 11:51:48 UTC
The branch main has been updated by andrew:

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

commit 202890922e31382f9b11bf5f78d3dd0350d69dc1
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-01-08 14:45:51 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-02-13 11:48:52 +0000

    sys: Simplify enabling EARLY_PRINTF uarts
    
    Support selecting the early uart with "options EARLY_PRINTF=foo" in
    the kernel configuration file. This allows us to not have to change
    source files when enabling EARLY_PRINTF, simplifying enabling it.
    
    New uart drivers can be enabled by defining a new early_printf_foo
    value to be unique, then using "#if CHECK_EARLY_PRINTF(foo)" to decide
    when to enable the uart.
    
    While here add pl011 early printf support.
    
    Reviewed by:    imp (earlier version)
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D43360
---
 sys/dev/uart/uart_dev_mvebu.c  | 11 +++--------
 sys/dev/uart/uart_dev_ns8250.c |  7 +++++--
 sys/dev/uart/uart_dev_pl011.c  | 14 ++++++++++++++
 sys/dev/uart/uart_dev_snps.c   | 19 ++++++++-----------
 sys/kern/kern_cons.c           | 12 ++++++++++++
 sys/sys/systm.h                |  9 +++++++++
 6 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/sys/dev/uart/uart_dev_mvebu.c b/sys/dev/uart/uart_dev_mvebu.c
index 921298ffb6c7..8f989aa0ca14 100644
--- a/sys/dev/uart/uart_dev_mvebu.c
+++ b/sys/dev/uart/uart_dev_mvebu.c
@@ -104,18 +104,15 @@
 /*
  * For debugging purposes
  */
-#if 0
-#ifdef EARLY_PRINTF
-#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
-#define	UART_REG_OFFSET 0x12000
+#if CHECK_EARLY_PRINTF(mvebu)
 static void
 uart_mvebu_early_putc(int c)
 {
 	volatile uint32_t *tsh;
 	volatile uint32_t *stat;
 
-	tsh = (uint32_t *)(SOCDEV_VA + UART_REG_OFFSET + UART_TSH);
-	stat = (uint32_t *)(SOCDEV_VA + UART_REG_OFFSET + UART_STAT);
+	tsh = (uint32_t *)(socdev_va + UART_REG_OFFSET + UART_TSH);
+	stat = (uint32_t *)(socdev_va + UART_REG_OFFSET + UART_STAT);
 
 	while(!(*stat & STAT_TX_RDY))
 		;
@@ -125,8 +122,6 @@ uart_mvebu_early_putc(int c)
 
 early_putc_t *early_putc = uart_mvebu_early_putc;
 #endif
-#endif
-#endif
 
 /*
  * Low-level UART interface.
diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c
index f211084cb013..090909fdf8d2 100644
--- a/sys/dev/uart/uart_dev_ns8250.c
+++ b/sys/dev/uart/uart_dev_ns8250.c
@@ -81,9 +81,12 @@ SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RWTUN,
  * To use early printf on x86, add the following to your kernel config:
  *
  * options UART_NS8250_EARLY_PORT=0x3f8
- * options EARLY_PRINTF
+ * options EARLY_PRINTF=ns8250
 */
-#if defined(EARLY_PRINTF) && (defined(__amd64__) || defined(__i386__))
+#if CHECK_EARLY_PRINTF(ns8250)
+#if !(defined(__amd64__) || defined(__i386__))
+#error ns8250 early putc is x86 specific as it uses inb/outb
+#endif
 static void
 uart_ns8250_early_putc(int c)
 {
diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c
index 4fd53ab67bf3..bfcf8cf1584e 100644
--- a/sys/dev/uart/uart_dev_pl011.c
+++ b/sys/dev/uart/uart_dev_pl011.c
@@ -249,6 +249,20 @@ uart_pl011_term(struct uart_bas *bas)
 {
 }
 
+#if CHECK_EARLY_PRINTF(pl011)
+static void
+uart_pl011_early_putc(int c)
+{
+	volatile uint32_t *fr = (uint32_t *)(socdev_va + UART_FR * 4);
+	volatile uint32_t *dr = (uint32_t *)(socdev_va + UART_DR * 4);
+
+	while ((*fr & FR_TXFF) != 0)
+		;
+	*dr = c & 0xff;
+}
+early_putc_t *early_putc = uart_pl011_early_putc;
+#endif /* CHECK_EARLY_PRINTF */
+
 static void
 uart_pl011_putc(struct uart_bas *bas, int c)
 {
diff --git a/sys/dev/uart/uart_dev_snps.c b/sys/dev/uart/uart_dev_snps.c
index b8b1f1f78142..b6efd1948b3e 100644
--- a/sys/dev/uart/uart_dev_snps.c
+++ b/sys/dev/uart/uart_dev_snps.c
@@ -54,18 +54,16 @@ struct snps_softc {
 /*
  * To use early printf on 64 bits Allwinner SoC, add to kernel config
  * options SOCDEV_PA=0x0
- * options SOCDEV_VA=0x40000000
- * options EARLY_PRINTF
+ * options EARLY_PRINTF=snps
  *
  * To use early printf on 32 bits Allwinner SoC, add to kernel config
  * options SOCDEV_PA=0x01C00000
  * options SOCDEV_VA=0x10000000
- * options EARLY_PRINTF
+ * options EARLY_PRINTF=snps
  *
  * remove the if 0
 */
-#if 0
-#ifdef EARLY_PRINTF
+#if CHECK_EARLY_PRINTF(snps)
 static void
 uart_snps_early_putc(int c)
 {
@@ -73,12 +71,12 @@ uart_snps_early_putc(int c)
 	volatile uint32_t *tx;
 
 #ifdef ALLWINNER_64
-	stat = (uint32_t *) (SOCDEV_VA + 0x1C2807C);
-	tx = (uint32_t *) (SOCDEV_VA + 0x1C28000);
+	stat = (uint32_t *) (socdev_va + 0x1C2807C);
+	tx = (uint32_t *) (socdev_va + 0x1C28000);
 #endif
 #ifdef ALLWINNER_32
-	stat = (uint32_t *) (SOCDEV_VA + 0x2807C);
-	tx = (uint32_t *) (SOCDEV_VA + 0x28000);
+	stat = (uint32_t *) (socdev_va + 0x2807C);
+	tx = (uint32_t *) (socdev_va + 0x28000);
 #endif
 
 	while ((*stat & (1 << 2)) == 0)
@@ -86,8 +84,7 @@ uart_snps_early_putc(int c)
 	*tx = c;
 }
 early_putc_t *early_putc = uart_snps_early_putc;
-#endif /* EARLY_PRINTF */
-#endif
+#endif /* CHECK_EARLY_PRINTF */
 
 static kobj_method_t snps_methods[] = {
 	KOBJMETHOD(uart_probe,		ns8250_bus_probe),
diff --git a/sys/kern/kern_cons.c b/sys/kern/kern_cons.c
index 462cd0c45758..a99699ed5bce 100644
--- a/sys/kern/kern_cons.c
+++ b/sys/kern/kern_cons.c
@@ -72,6 +72,18 @@
 #include <machine/cpu.h>
 #include <machine/clock.h>
 
+/*
+ * Check for 'options EARLY_PRINTF' that may have been used in old kernel
+ * config files. If you are hitting this error you should update your
+ * config to use 'options EARLY_PRINTF=<device name>', e.g. with the
+ * Arm pl011 use:
+ *
+ * options EARLY_PRINTF=pl011
+ */
+#if CHECK_EARLY_PRINTF(1)
+#error Update your config to use 'options EARLY_PRINTF=<device name>'
+#endif
+
 static MALLOC_DEFINE(M_TTYCONS, "tty console", "tty console handling");
 
 struct cn_device {
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 376a35e7e8e2..f72f82c100dc 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -208,6 +208,15 @@ critical_exit(void)
 #ifdef  EARLY_PRINTF
 typedef void early_putc_t(int ch);
 extern early_putc_t *early_putc;
+#define	CHECK_EARLY_PRINTF(x)	\
+    __CONCAT(early_printf_, EARLY_PRINTF) == __CONCAT(early_printf_, x)
+#define	early_printf_1		1
+#define	early_printf_mvebu	2
+#define	early_printf_ns8250	3
+#define	early_printf_pl011	4
+#define	early_printf_snps	5
+#else
+#define	CHECK_EARLY_PRINTF(x)	0
 #endif
 int	kvprintf(char const *, void (*)(int, void*), void *, int,
 	    __va_list) __printflike(1, 0);