From eba1a249dfc6ca98f5d10d9a56a53e3995cef1fc Mon Sep 17 00:00:00 2001 From: Andrew Turner Date: Mon, 21 Nov 2016 19:26:58 +0000 Subject: [PATCH] Add support to find the arm64 serial using the ACPI tables. This uses the Serial Port Console Redirection Table to find the device to use. Obtained from: ABT Systems Ltd Sponsored by: The FreeBSD Foundation --- sys/arm64/acpica/acpi_machdep.c | 18 +++++++ sys/arm64/include/acpica_machdep.h | 7 +++ sys/dev/uart/uart_cpu_acpi.h | 1 + sys/dev/uart/uart_cpu_arm64.c | 84 +++++++++++++++++++++++++++++- sys/dev/uart/uart_dev_pl011.c | 13 +++-- 5 files changed, 117 insertions(+), 6 deletions(-) diff --git a/sys/arm64/acpica/acpi_machdep.c b/sys/arm64/acpica/acpi_machdep.c index da07cfcb0606..28216a86b382 100644 --- a/sys/arm64/acpica/acpi_machdep.c +++ b/sys/arm64/acpica/acpi_machdep.c @@ -44,6 +44,8 @@ __FBSDID("$FreeBSD$"); #include +extern struct bus_space memmap_bus; + int acpi_machdep_init(device_t dev) { @@ -215,3 +217,19 @@ acpi_find_table(const char *sig) return (addr); } + +int +acpi_map_addr(struct acpi_generic_address *addr, bus_space_tag_t *tag, + bus_space_handle_t *handle, bus_size_t size) +{ + bus_addr_t phys; + + /* Check if the device is Memory mapped */ + if (addr->SpaceId != 0) + return (ENXIO); + + phys = addr->Address; + *tag = &memmap_bus; + + return (bus_space_map(*tag, phys, size, 0, handle)); +} diff --git a/sys/arm64/include/acpica_machdep.h b/sys/arm64/include/acpica_machdep.h index 9a3434a2bbab..282c79f5eaec 100644 --- a/sys/arm64/include/acpica_machdep.h +++ b/sys/arm64/include/acpica_machdep.h @@ -39,6 +39,8 @@ #ifdef _KERNEL +#include + /* Only use the reduced hardware model */ #define ACPI_REDUCED_HARDWARE 1 @@ -50,6 +52,11 @@ void *acpi_map_table(vm_paddr_t pa, const char *sig); void acpi_unmap_table(void *table); vm_paddr_t acpi_find_table(const char *sig); +struct acpi_generic_address; + +int acpi_map_addr(struct acpi_generic_address *, bus_space_tag_t *, + bus_space_handle_t *, bus_size_t); + #endif /* _KERNEL */ #endif /* __ACPICA_MACHDEP_H__ */ diff --git a/sys/dev/uart/uart_cpu_acpi.h b/sys/dev/uart/uart_cpu_acpi.h index afdd93da99bf..30cfa4e19388 100644 --- a/sys/dev/uart/uart_cpu_acpi.h +++ b/sys/dev/uart/uart_cpu_acpi.h @@ -40,6 +40,7 @@ struct uart_class; struct acpi_uart_compat_data { const char *hid; struct uart_class *clas; + uint16_t port_subtype; }; /* diff --git a/sys/dev/uart/uart_cpu_arm64.c b/sys/dev/uart/uart_cpu_arm64.c index 36193414bf1e..ce620e973b29 100644 --- a/sys/dev/uart/uart_cpu_arm64.c +++ b/sys/dev/uart/uart_cpu_arm64.c @@ -48,6 +48,12 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef DEV_ACPI +#include +#include +#include +#endif + #ifdef FDT #include #include @@ -72,6 +78,76 @@ uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) return ((pmap_kextract(b1->bsh) == pmap_kextract(b2->bsh)) ? 1 : 0); } +#ifdef DEV_ACPI +static struct acpi_uart_compat_data * +uart_cpu_acpi_scan(uint8_t interface_type) +{ + struct acpi_uart_compat_data **cd; + + SET_FOREACH(cd, uart_acpi_class_and_device_set) { + if ((*cd)->port_subtype == interface_type) + return (*cd); + } + + SET_FOREACH(cd, uart_acpi_class_set) { + if ((*cd)->port_subtype == interface_type) + return (*cd); + } + + return (NULL); +} + +static int +uart_cpu_acpi_probe(struct uart_class **classp, bus_space_tag_t *bst, + bus_space_handle_t *bsh, int *baud, u_int *rclk, u_int *shiftp) +{ + struct acpi_uart_compat_data *cd; + ACPI_TABLE_SPCR *spcr; + vm_paddr_t spcr_physaddr; + int err; + + err = ENXIO; + spcr_physaddr = acpi_find_table(ACPI_SIG_SPCR); + if (spcr_physaddr == 0) + return (ENXIO); + + spcr = acpi_map_table(spcr_physaddr, ACPI_SIG_SPCR); + + cd = uart_cpu_acpi_scan(spcr->InterfaceType); + if (cd == NULL) + goto out; + + switch(spcr->BaudRate) { + case 3: + *baud = 9600; + break; + case 4: + *baud = 19200; + break; + case 6: + *baud = 57600; + break; + case 7: + *baud = 115200; + break; + default: + goto out; + } + + err = acpi_map_addr(&spcr->SerialPort, bst, bsh, PAGE_SIZE); + if (err != 0) + goto out; + + *classp = cd->clas; + *rclk = 0; + *shiftp = 2; + +out: + acpi_unmap_table(spcr); + return (err); +} +#endif + int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { @@ -91,8 +167,14 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) return (ENXIO); err = ENXIO; +#ifdef DEV_ACPI + err = uart_cpu_acpi_probe(&class, &bst, &bsh, &br, &rclk, &shift); +#endif #ifdef FDT - err = uart_cpu_fdt_probe(&class, &bst, &bsh, &br, &rclk, &shift); + if (err != 0) { + err = uart_cpu_fdt_probe(&class, &bst, &bsh, &br, &rclk, + &shift); + } #endif if (err != 0) return (err); diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index 8604477097a6..49f22b33e6bb 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -38,15 +38,18 @@ __FBSDID("$FreeBSD$"); #include #include -#ifdef DEV_ACPI -#include -#endif #ifdef FDT #include #endif #include #include "uart_if.h" +#ifdef DEV_ACPI +#include +#include +#include +#endif + #include /* PL011 UART registers and masks*/ @@ -296,8 +299,8 @@ UART_FDT_CLASS_AND_DEVICE(compat_data); #ifdef DEV_ACPI static struct acpi_uart_compat_data acpi_compat_data[] = { - {"ARMH0011", &uart_pl011_class}, - {NULL, NULL}, + {"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011}, + {NULL, NULL, 0}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); #endif