git: 097bd33dd7a6 - main - uart: DBG2 support to find the debug uart

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Fri, 17 May 2024 16:12:49 UTC
The branch main has been updated by andrew:

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

commit 097bd33dd7a687cd3ad7fd4bc7ededa3b9e00e28
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2024-03-12 18:15:29 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2024-05-17 16:07:15 +0000

    uart: DBG2 support to find the debug uart
    
    The Debug Port Table 2 (DBG2) contains information on which devices
    can be used for debugging purposes.
    
    Add support to the uart driver to use the DBG2 table when enabled from
    loader.
    
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D44359
---
 sys/dev/uart/uart_cpu_acpi.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/sys/dev/uart/uart_cpu_acpi.c b/sys/dev/uart/uart_cpu_acpi.c
index 9c9ffc1e3194..53fe459e64a1 100644
--- a/sys/dev/uart/uart_cpu_acpi.c
+++ b/sys/dev/uart/uart_cpu_acpi.c
@@ -210,12 +210,95 @@ out:
 	return (error);
 }
 
+static int
+uart_cpu_acpi_dbg2(struct uart_devinfo *di)
+{
+	vm_paddr_t dbg2_physaddr;
+	ACPI_TABLE_DBG2 *dbg2;
+	ACPI_DBG2_DEVICE *dbg2_dev;
+	ACPI_GENERIC_ADDRESS *base_address;
+	struct acpi_uart_compat_data *cd;
+	struct uart_class *class;
+	int error;
+	bool found;
+
+	/* Look for the SPCR table. */
+	dbg2_physaddr = acpi_find_table(ACPI_SIG_DBG2);
+	if (dbg2_physaddr == 0)
+		return (ENXIO);
+
+	dbg2 = acpi_map_table(dbg2_physaddr, ACPI_SIG_DBG2);
+	if (dbg2 == NULL) {
+		printf("Unable to map the DBG2 table!\n");
+		return (ENXIO);
+	}
+
+	error = ENXIO;
+
+	dbg2_dev = (ACPI_DBG2_DEVICE *)((vm_offset_t)dbg2 + dbg2->InfoOffset);
+	found = false;
+	while ((vm_offset_t)dbg2_dev + dbg2_dev->Length <=
+	    (vm_offset_t)dbg2 + dbg2->Header.Length) {
+		if (dbg2_dev->PortType != ACPI_DBG2_SERIAL_PORT)
+			goto next;
+
+		/* XXX: Too restrictive? */
+		if (dbg2_dev->RegisterCount != 1)
+			goto next;
+
+		cd = uart_cpu_acpi_scan(dbg2_dev->PortSubtype);
+		if (cd == NULL)
+			goto next;
+
+		class = cd->cd_class;
+		base_address = (ACPI_GENERIC_ADDRESS *)
+		    ((vm_offset_t)dbg2_dev + dbg2_dev->BaseAddressOffset);
+
+		error = uart_cpu_acpi_init_devinfo(di, class, base_address);
+		if (error == 0) {
+			found = true;
+			break;
+		}
+
+next:
+		dbg2_dev = (ACPI_DBG2_DEVICE *)
+		    ((vm_offset_t)dbg2_dev + dbg2_dev->Length);
+	}
+	if (!found)
+		goto out;
+
+	/* XXX: Find the correct value */
+	di->baudrate = 115200;
+
+	/* Apply device tweaks. */
+	if ((cd->cd_quirks & UART_F_IGNORE_SPCR_REGSHFT) ==
+	    UART_F_IGNORE_SPCR_REGSHFT) {
+		di->bas.regshft = cd->cd_regshft;
+	}
+
+	/* Create a bus space handle. */
+	error = bus_space_map(di->bas.bst, base_address->Address,
+	    uart_getrange(class), 0, &di->bas.bsh);
+
+out:
+	acpi_unmap_table(dbg2);
+	return (error);
+}
+
 int
 uart_cpu_acpi_setup(int devtype, struct uart_devinfo *di)
 {
+	char *cp;
+
 	switch(devtype) {
 	case UART_DEV_CONSOLE:
 		return (uart_cpu_acpi_spcr(devtype, di));
+	case UART_DEV_DBGPORT:
+		/* Use the Debug Port Table 2 (DBG2) to find a debug uart */
+		cp = kern_getenv("hw.acpi.enable_dbg2");
+		if (cp != NULL && strcasecmp(cp, "yes") == 0)
+			return (uart_cpu_acpi_dbg2(di));
+		break;
 	}
 	return (ENXIO);
 }