diff options
Diffstat (limited to 'sys/dev/uart')
-rw-r--r-- | sys/dev/uart/uart.h | 2 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus.h | 1 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus_fdt.c | 3 | ||||
-rw-r--r-- | sys/dev/uart/uart_bus_pci.c | 14 | ||||
-rw-r--r-- | sys/dev/uart/uart_core.c | 19 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_acpi.c | 151 | ||||
-rw-r--r-- | sys/dev/uart/uart_cpu_fdt.c | 2 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_ns8250.c | 86 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_ns8250.h | 1 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_pl011.c | 48 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_quicc.c | 4 | ||||
-rw-r--r-- | sys/dev/uart/uart_dev_z8530.c | 4 | ||||
-rw-r--r-- | sys/dev/uart/uart_subr.c | 17 | ||||
-rw-r--r-- | sys/dev/uart/uart_tty.c | 2 |
14 files changed, 280 insertions, 74 deletions
diff --git a/sys/dev/uart/uart.h b/sys/dev/uart/uart.h index 4cdec00c9829..b9401996e655 100644 --- a/sys/dev/uart/uart.h +++ b/sys/dev/uart/uart.h @@ -40,11 +40,13 @@ struct uart_bas { bus_space_tag_t bst; bus_space_handle_t bsh; + void *driver1; u_int chan; u_int rclk; u_int regshft; u_int regiowidth; u_int busy_detect; + u_int rclk_guess;/* if rclk == 0, use baud + divisor to compute rclk */ }; #define uart_regofs(bas, reg) ((reg) << (bas)->regshft) diff --git a/sys/dev/uart/uart_bus.h b/sys/dev/uart/uart_bus.h index ccf8ad06a8ec..a605e3d20be7 100644 --- a/sys/dev/uart/uart_bus.h +++ b/sys/dev/uart/uart_bus.h @@ -56,7 +56,6 @@ /* UART quirk flags */ #define UART_F_BUSY_DETECT 0x1 -#define UART_F_IGNORE_SPCR_REGSHFT 0x2 /* * UART class & instance (=softc) diff --git a/sys/dev/uart/uart_bus_fdt.c b/sys/dev/uart/uart_bus_fdt.c index 7725d09e212b..431f2962adb2 100644 --- a/sys/dev/uart/uart_bus_fdt.c +++ b/sys/dev/uart/uart_bus_fdt.c @@ -234,7 +234,8 @@ uart_cpu_fdt_probe(struct uart_class **classp, bus_space_tag_t *bst, (struct uart_class *)uart_fdt_find_by_node(node, 1); if (class == NULL) return (ENXIO); - clk = 0; + if (uart_fdt_get_clock(node, &clk) != 0) + clk = 0; } /* diff --git a/sys/dev/uart/uart_bus_pci.c b/sys/dev/uart/uart_bus_pci.c index 5f82ef9307d0..14ac213066b8 100644 --- a/sys/dev/uart/uart_bus_pci.c +++ b/sys/dev/uart/uart_bus_pci.c @@ -106,6 +106,20 @@ static const struct pci_id pci_ns8250_ids[] = { { 0x131f, 0x2000, 0xffff, 0, "Siig CyberSerial (1-port) 16550", 0x10 }, { 0x131f, 0x2001, 0xffff, 0, "Siig CyberSerial (1-port) 16650", 0x10 }, { 0x131f, 0x2002, 0xffff, 0, "Siig CyberSerial (1-port) 16850", 0x10 }, +{ 0x135a, 0x0a61, 0xffff, 0, "Brainboxes UC-324", 0x18 }, +{ 0x135a, 0x0aa1, 0xffff, 0, "Brainboxes UC-246", 0x18 }, +{ 0x135a, 0x0aa2, 0xffff, 0, "Brainboxes UC-246", 0x18 }, +{ 0x135a, 0x0d60, 0xffff, 0, "Intashield IS-100", 0x18 }, +{ 0x135a, 0x0da0, 0xffff, 0, "Intashield IS-300", 0x18 }, +{ 0x135a, 0x4000, 0xffff, 0, "Brainboxes PX-420", 0x10 }, +{ 0x135a, 0x4001, 0xffff, 0, "Brainboxes PX-431", 0x10 }, +{ 0x135a, 0x4002, 0xffff, 0, "Brainboxes PX-820", 0x10 }, +{ 0x135a, 0x4003, 0xffff, 0, "Brainboxes PX-831", 0x10 }, +{ 0x135a, 0x4004, 0xffff, 0, "Brainboxes PX-246", 0x10 }, +{ 0x135a, 0x4005, 0xffff, 0, "Brainboxes PX-101", 0x10 }, +{ 0x135a, 0x4006, 0xffff, 0, "Brainboxes PX-257", 0x10 }, +{ 0x135a, 0x4008, 0xffff, 0, "Brainboxes PX-846", 0x10 }, +{ 0x135a, 0x4009, 0xffff, 0, "Brainboxes PX-857", 0x10 }, { 0x135c, 0x0190, 0xffff, 0, "Quatech SSCLP-100", 0x18 }, { 0x135c, 0x01c0, 0xffff, 0, "Quatech SSCLP-200/300", 0x18 }, { 0x135e, 0x7101, 0xffff, 0, "Sealevel Systems Single Port RS-232/422/485/530", diff --git a/sys/dev/uart/uart_core.c b/sys/dev/uart/uart_core.c index c2bc818a6fc2..0ee43f6d2d94 100644 --- a/sys/dev/uart/uart_core.c +++ b/sys/dev/uart/uart_core.c @@ -38,11 +38,11 @@ #include <sys/malloc.h> #include <sys/queue.h> #include <sys/reboot.h> +#include <sys/stdarg.h> #include <sys/sysctl.h> #include <machine/bus.h> #include <sys/rman.h> #include <machine/resource.h> -#include <machine/stdarg.h> #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> @@ -559,13 +559,19 @@ uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int uart_cpu_eqres(&sc->sc_bas, &sysdev->bas)) { /* XXX check if ops matches class. */ sc->sc_sysdev = sysdev; - sysdev->bas.rclk = sc->sc_bas.rclk; - } + if (sysdev->bas.rclk != 0) { + /* Let the boot sequence control */ + sc->sc_bas.rclk = sysdev->bas.rclk; + } else { + /* Boot didn't set it, use use class */ + sysdev->bas.rclk = sc->sc_bas.rclk; + } + } } error = UART_PROBE(sc); bus_release_resource(dev, sc->sc_rtype, sc->sc_rrid, sc->sc_rres); - return ((error) ? error : BUS_PROBE_DEFAULT); + return ((error) ? error : 0); } int @@ -746,6 +752,11 @@ uart_bus_attach(device_t dev) "rx_overruns", CTLFLAG_RD, &sc->sc_rxoverruns, 0, "Receive overruns"); + SYSCTL_ADD_INT(device_get_sysctl_ctx(dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, + "rclk", CTLFLAG_RD, &sc->sc_bas.rclk, 0, + "Baud clock for device"); + return (0); fail: diff --git a/sys/dev/uart/uart_cpu_acpi.c b/sys/dev/uart/uart_cpu_acpi.c index 9c9ffc1e3194..7382c47a8db6 100644 --- a/sys/dev/uart/uart_cpu_acpi.c +++ b/sys/dev/uart/uart_cpu_acpi.c @@ -167,40 +167,60 @@ uart_cpu_acpi_spcr(int devtype, struct uart_devinfo *di) if (error != 0) goto out; - switch (spcr->BaudRate) { - case 0: - /* Special value; means "keep current value unchanged". */ - di->baudrate = 0; - break; - case 3: - di->baudrate = 9600; - break; - case 4: - di->baudrate = 19200; - break; - case 6: - di->baudrate = 57600; - break; - case 7: - di->baudrate = 115200; - break; - default: - printf("SPCR has reserved BaudRate value: %d!\n", - (int)spcr->BaudRate); - goto out; + /* + * SPCR Rev 4 and newer allow a precise baudrate to be passed in for + * things like 1.5M or 2.0M. If we have that, then use that value, + * otherwise try to decode the older enumeration. + */ + if (spcr->Header.Revision >= 4 && spcr->PreciseBaudrate != 0) { + di->baudrate = spcr->PreciseBaudrate; + } else { + switch (spcr->BaudRate) { + case 0: + /* Special value; means "keep current value unchanged". */ + di->baudrate = 0; + break; + case 3: + di->baudrate = 9600; + break; + case 4: + di->baudrate = 19200; + break; + case 6: + di->baudrate = 57600; + break; + case 7: + di->baudrate = 115200; + break; + default: + printf("SPCR has reserved BaudRate value: %d!\n", + (int)spcr->BaudRate); + goto out; + } } + + /* + * Rev 3 and newer can specify a rclk, use it if it's there. It's + * defined to be 0 when it's not known, and we've initialized rclk to 0 + * in uart_cpu_acpi_init_devinfo, so we don't have to test for it. + */ + if (spcr->Header.Revision >= 3) + di->bas.rclk = spcr->UartClkFreq; + + /* + * If no rclk is set, then we will assume the BIOS has configured the + * hardware at the stated baudrate, so we can use it to guess the rclk + * relatively accurately, so make a note for later. + */ + if (di->bas.rclk == 0) + di->bas.rclk_guess = 1; + if (spcr->PciVendorId != PCIV_INVALID && spcr->PciDeviceId != PCIV_INVALID) { di->pci_info.vendor = spcr->PciVendorId; di->pci_info.device = spcr->PciDeviceId; } - /* 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, spcr->SerialPort.Address, uart_getrange(class), 0, &di->bas.bsh); @@ -210,12 +230,89 @@ 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 DBG2 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 *)((uintptr_t)dbg2 + dbg2->InfoOffset); + found = false; + while ((uintptr_t)dbg2_dev + dbg2_dev->Length <= + (uintptr_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 *) + ((uintptr_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 *) + ((uintptr_t)dbg2_dev + dbg2_dev->Length); + } + if (!found) + goto out; + + /* XXX: Find the correct value */ + di->baudrate = 115200; + + /* 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); } diff --git a/sys/dev/uart/uart_cpu_fdt.c b/sys/dev/uart/uart_cpu_fdt.c index 1cc1c795f29f..fd1647cd78aa 100644 --- a/sys/dev/uart/uart_cpu_fdt.c +++ b/sys/dev/uart/uart_cpu_fdt.c @@ -81,7 +81,7 @@ uart_cpu_getdev(int devtype, struct uart_devinfo *di) /* Allow overriding the FDT using the environment. */ class = &uart_ns8250_class; err = uart_getenv(devtype, di, class); - if (!err) + if (err == 0) return (0); err = uart_cpu_fdt_probe(&class, &bst, &bsh, &br, &rclk, diff --git a/sys/dev/uart/uart_dev_ns8250.c b/sys/dev/uart/uart_dev_ns8250.c index 16c3cb2fc5a9..0f19ede6d9df 100644 --- a/sys/dev/uart/uart_dev_ns8250.c +++ b/sys/dev/uart/uart_dev_ns8250.c @@ -77,6 +77,11 @@ static int broken_txfifo = 0; SYSCTL_INT(_hw, OID_AUTO, broken_txfifo, CTLFLAG_RWTUN, &broken_txfifo, 0, "UART FIFO has QEMU emulation bug"); +static int uart_noise_threshold = 0; +SYSCTL_INT(_hw, OID_AUTO, uart_noise_threshold, CTLFLAG_RWTUN, + &uart_noise_threshold, 0, + "Number of UART RX interrupts where TX is not ready, before data is discarded"); + /* * To use early printf on x86, add the following to your kernel config: * @@ -126,11 +131,11 @@ ns8250_clrint(struct uart_bas *bas) } } -static int -ns8250_delay(struct uart_bas *bas) +static uint32_t +ns8250_get_divisor(struct uart_bas *bas) { - int divisor; - u_char lcr; + uint32_t divisor; + uint8_t lcr; lcr = uart_getreg(bas, REG_LCR); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); @@ -140,6 +145,16 @@ ns8250_delay(struct uart_bas *bas) uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); + return (divisor); +} + +static int +ns8250_delay(struct uart_bas *bas) +{ + int divisor; + + divisor = ns8250_get_divisor(bas); + /* 1/10th the time to transmit 1 character (estimate). */ if (divisor <= 134) return (16000000 * divisor / bas->rclk); @@ -187,7 +202,7 @@ ns8250_drain(struct uart_bas *bas, int what) while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) DELAY(delay); if (limit == 0) { - /* printf("ns8250: transmitter appears stuck... "); */ + /* printf("uart: ns8250: transmitter appears stuck... "); */ return (EIO); } } @@ -215,7 +230,7 @@ ns8250_drain(struct uart_bas *bas, int what) DELAY(delay << 2); } if (limit == 0) { - /* printf("ns8250: receiver appears broken... "); */ + /* printf("uart: ns8250: receiver appears broken... "); */ return (EIO); } } @@ -250,12 +265,12 @@ ns8250_flush(struct uart_bas *bas, int what) * https://github.com/rust-vmm/vm-superio/issues/83 */ lsr = uart_getreg(bas, REG_LSR); - if (((lsr & LSR_TEMT) == 0) && (what & UART_FLUSH_TRANSMITTER)) + if (((lsr & LSR_THRE) == 0) && (what & UART_FLUSH_TRANSMITTER)) drain |= UART_DRAIN_TRANSMITTER; if ((lsr & LSR_RXRDY) && (what & UART_FLUSH_RECEIVER)) drain |= UART_DRAIN_RECEIVER; if (drain != 0) { - printf("ns8250: UART FCR is broken\n"); + printf("uart: ns8250: UART FCR is broken (%#x)\n", drain); ns8250_drain(bas, drain); } } @@ -284,8 +299,8 @@ ns8250_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, lcr |= LCR_STOPB; lcr |= parity << 3; - /* Set baudrate. */ - if (baudrate > 0) { + /* Set baudrate if we know a rclk and both are not 0. */ + if (baudrate > 0 && bas->rclk > 0) { divisor = ns8250_divisor(bas->rclk, baudrate); if (divisor == 0) return (EINVAL); @@ -349,10 +364,6 @@ ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, { u_char ier; - if (bas->rclk == 0) - bas->rclk = DEFAULT_RCLK; - ns8250_param(bas, baudrate, databits, stopbits, parity); - /* Disable all interrupt sources. */ /* * We use 0xe0 instead of 0xf0 as the mask because the XScale PXA @@ -363,6 +374,30 @@ ns8250_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, uart_setreg(bas, REG_IER, ier); uart_barrier(bas); + /* + * Loader tells us to infer the rclk when it sets xo to 0 in + * hw.uart.console. 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. + */ + if (bas->rclk_guess && bas->rclk == 0 && baudrate != 0) { + uint32_t div; + + div = ns8250_get_divisor(bas); + bas->rclk = baudrate * div * 16; + } + + /* + * Pick a default because we just don't know. This likely needs future + * refinement, but that's hard outside of consoles to know what to use. + * But defer as long as possible if there's no defined baud rate. + */ + if (bas->rclk == 0 && baudrate != 0) + bas->rclk = DEFAULT_RCLK; + + ns8250_param(bas, baudrate, databits, stopbits, parity); + /* Disable the FIFO (if present). */ uart_setreg(bas, REG_FCR, 0); uart_barrier(bas); @@ -460,9 +495,11 @@ UART_CLASS(uart_ns8250_class); static struct acpi_uart_compat_data acpi_compat_data[] = { {"AMD0020", &uart_ns8250_class, 0, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, {"AMDI0020", &uart_ns8250_class, 0, 2, 0, 48000000, UART_F_BUSY_DETECT, "AMD / Synopsys Designware UART"}, + {"APMC0D08", &uart_ns8250_class, ACPI_DBG2_16550_COMPATIBLE, 2, 4, 0, 0, "APM compatible UART"}, {"MRVL0001", &uart_ns8250_class, ACPI_DBG2_16550_SUBSET, 2, 0, 200000000, UART_F_BUSY_DETECT, "Marvell / Synopsys Designware UART"}, {"SCX0006", &uart_ns8250_class, 0, 2, 0, 62500000, UART_F_BUSY_DETECT, "SynQuacer / Synopsys Designware UART"}, {"HISI0031", &uart_ns8250_class, 0, 2, 0, 200000000, UART_F_BUSY_DETECT, "HiSilicon / Synopsys Designware UART"}, + {"INTC1006", &uart_ns8250_class, 0, 2, 0, 25000000, 0, "Intel ARM64 UART"}, {"NXP0018", &uart_ns8250_class, 0, 0, 0, 350000000, UART_F_BUSY_DETECT, "NXP / Synopsys Designware UART"}, {"PNP0500", &uart_ns8250_class, 0, 0, 0, 0, 0, "Standard PC COM port"}, {"PNP0501", &uart_ns8250_class, 0, 0, 0, 0, 0, "16550A-compatible COM port"}, @@ -725,14 +762,7 @@ ns8250_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) uart_barrier(bas); break; case UART_IOCTL_BAUD: - lcr = uart_getreg(bas, REG_LCR); - uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); - uart_barrier(bas); - divisor = uart_getreg(bas, REG_DLL) | - (uart_getreg(bas, REG_DLH) << 8); - uart_barrier(bas); - uart_setreg(bas, REG_LCR, lcr); - uart_barrier(bas); + divisor = ns8250_get_divisor(bas); baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; if (baudrate > 0) *(int*)data = baudrate; @@ -987,6 +1017,7 @@ int ns8250_bus_receive(struct uart_softc *sc) { struct uart_bas *bas; + struct ns8250_softc *ns8250 = (struct ns8250_softc *)sc; int xc; uint8_t lsr; @@ -998,6 +1029,17 @@ ns8250_bus_receive(struct uart_softc *sc) sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } + /* Filter out possible noise on the line. + * Expect that the device should be able to transmit as well as + * receive, so if we receive too many characters before transmit + * is ready, it's probably noise. + */ + if ((lsr & (LSR_TXRDY | LSR_TEMT)) == 0 && + uart_noise_threshold > 0) { + if (++ns8250->noise_count >= uart_noise_threshold) + break; + } else + ns8250->noise_count = 0; xc = uart_getreg(bas, REG_DATA); if (lsr & LSR_FE) xc |= UART_STAT_FRAMERR; diff --git a/sys/dev/uart/uart_dev_ns8250.h b/sys/dev/uart/uart_dev_ns8250.h index 324ff72f6e5d..e8a17e96c268 100644 --- a/sys/dev/uart/uart_dev_ns8250.h +++ b/sys/dev/uart/uart_dev_ns8250.h @@ -41,6 +41,7 @@ struct ns8250_softc { uint8_t ier_mask; uint8_t ier_rxbits; uint8_t busy_detect; + int noise_count; }; extern struct uart_ops uart_ns8250_ops; diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index daba9d19704c..a0d5a5b1c7e2 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -172,6 +172,27 @@ static int uart_pl011_probe(struct uart_bas *bas) { + /* + * Versions of QEMU before 41f7b58b634e (8.3) reported bogus values for + * this tabel. The PL011 IP is always 32-bits wide and should be shifted + * 2 to match the 4-byte size of the data. QEMU reported these values + * incorrectly before that. + * https://github.com/qemu/qemu/commit/41f7b58b634ec3b60ae874375d2bbb61d790971e + * + * In additon, other hardware vendors also reported this value + * incorrectly. It's not tied to what the ACPI device node is, but was a + * misunderstanding coupled with a Linux driver that didn't need the + * right values. Quirks used to be used to ignore the bad values, now we + * detect the historic mistake and override (to allow for a future where + * we may need to override these values). + * + * PL011 Docs: https://developer.arm.com/documentation/ddi0183/latest/ + */ + if (bas->regshft == 0 || bas->regiowidth == 1) { + bas->regshft = 2; + bas->regiowidth = 4; + } + return (0); } @@ -231,6 +252,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 @@ -338,7 +377,8 @@ static struct uart_class uart_pl011_class = { .uc_ops = &uart_pl011_ops, .uc_range = 0x48, .uc_rclk = 0, - .uc_rshift = 2 + .uc_rshift = 2, + .uc_riowidth = 4, }; UART_CLASS(uart_pl011_class); @@ -352,9 +392,9 @@ UART_FDT_CLASS_AND_DEVICE(fdt_compat_data); #ifdef DEV_ACPI static struct acpi_uart_compat_data acpi_compat_data[] = { - {"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"}, - {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT, 2, 0, 0, UART_F_IGNORE_SPCR_REGSHFT, "uart pl011"}, + {"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC, 2, 0, 0, 0, "uart pl011"}, + {"ARMHB000", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_32BIT, 2, 0, 0, 0, "uart pl011"}, {NULL, NULL, 0, 0, 0, 0, 0, NULL}, }; UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data); diff --git a/sys/dev/uart/uart_dev_quicc.c b/sys/dev/uart/uart_dev_quicc.c index bd735f2da6f4..d6a8846b874e 100644 --- a/sys/dev/uart/uart_dev_quicc.c +++ b/sys/dev/uart/uart_dev_quicc.c @@ -412,7 +412,6 @@ quicc_bus_param(struct uart_softc *sc, int baudrate, int databits, static int quicc_bus_probe(struct uart_softc *sc) { - char buf[80]; int error; error = quicc_probe(&sc->sc_bas); @@ -422,8 +421,7 @@ quicc_bus_probe(struct uart_softc *sc) sc->sc_rxfifosz = 1; sc->sc_txfifosz = 1; - snprintf(buf, sizeof(buf), "quicc, channel %d", sc->sc_bas.chan); - device_set_desc_copy(sc->sc_dev, buf); + device_set_descf(sc->sc_dev, "quicc, channel %d", sc->sc_bas.chan); return (0); } diff --git a/sys/dev/uart/uart_dev_z8530.c b/sys/dev/uart/uart_dev_z8530.c index 2ca480a5690d..45bf63f20bb2 100644 --- a/sys/dev/uart/uart_dev_z8530.c +++ b/sys/dev/uart/uart_dev_z8530.c @@ -509,7 +509,6 @@ z8530_bus_param(struct uart_softc *sc, int baudrate, int databits, static int z8530_bus_probe(struct uart_softc *sc) { - char buf[80]; int error; char ch; @@ -522,8 +521,7 @@ z8530_bus_probe(struct uart_softc *sc) ch = sc->sc_bas.chan - 1 + 'A'; - snprintf(buf, sizeof(buf), "z8530, channel %c", ch); - device_set_desc_copy(sc->sc_dev, buf); + device_set_descf(sc->sc_dev, "z8530, channel %c", ch); return (0); } diff --git a/sys/dev/uart/uart_subr.c b/sys/dev/uart/uart_subr.c index 03c7fd8caea9..ca127b3a956e 100644 --- a/sys/dev/uart/uart_subr.c +++ b/sys/dev/uart/uart_subr.c @@ -185,6 +185,7 @@ out: * mm = Memory mapped I/O address * pa = Parity * rs = Register shift + * rw = Register width * sb = Stopbits * xo = Device clock (xtal oscillator) * @@ -200,13 +201,6 @@ uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) int error; /* - * All uart_class references are weak. Make sure the default - * device class has been compiled-in. - */ - if (class == NULL) - return (ENXIO); - - /* * Check the environment variables "hw.uart.console" and * "hw.uart.dbgport". These variables, when present, specify * which UART port is to be used as serial console or debug @@ -278,6 +272,8 @@ uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) break; case UART_TAG_XO: di->bas.rclk = uart_parse_long(&spec); + if (di->bas.rclk == 0) + di->bas.rclk_guess = 1; break; default: goto inval; @@ -298,6 +294,13 @@ uart_getenv(int devtype, struct uart_devinfo *di, struct uart_class *class) freeenv(cp); /* + * The default uart_class reference is weak. Make sure the default + * device class has been compiled-in or we've set one with dt=. + */ + if (class == NULL) + return (ENXIO); + + /* * Accept only the well-known baudrates. Any invalid baudrate * is silently replaced with a 0-valued baudrate. The 0 baudrate * has special meaning. It means that we're not supposed to diff --git a/sys/dev/uart/uart_tty.c b/sys/dev/uart/uart_tty.c index faae077916f3..d15d1d0c6ac2 100644 --- a/sys/dev/uart/uart_tty.c +++ b/sys/dev/uart/uart_tty.c @@ -36,11 +36,11 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/reboot.h> +#include <sys/stdarg.h> #include <machine/bus.h> #include <sys/rman.h> #include <sys/tty.h> #include <machine/resource.h> -#include <machine/stdarg.h> #include <dev/uart/uart.h> #include <dev/uart/uart_bus.h> |