add snps IP uart support / genaralize UART

This is an amalgam of a patch by Doug Ambrisko to
generalize uart_acpi_find_device, imp moving the
ACPI table to uart_dev_ns8250.c and advice by jhb
to work around a bug in the EPYC 3151 BIOS
(the BIOS incorrectly marks the serial ports as
disabled)

Reviewed by: imp
MFC after: 8 weeks
Differential Revision: https://reviews.freebsd.org/D16432
This commit is contained in:
Matt Macy 2018-08-19 21:10:21 +00:00
parent 8d67357c5c
commit 381388b9c4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=338074
27 changed files with 95 additions and 83 deletions

View File

@ -216,7 +216,7 @@ tegra_uart_probe(device_t dev)
device_printf(dev, "Cannot enable UART clock: %d\n", rv);
return (ENXIO);
}
return (uart_bus_probe(dev, shift, 0, (int)freq, 0, 0));
return (uart_bus_probe(dev, shift, 0, (int)freq, 0, 0, 0));
}
static int

View File

@ -2221,6 +2221,15 @@ acpi_DeviceIsPresent(device_t dev)
return (FALSE);
status = acpi_GetInteger(h, "_STA", &s);
/*
* Onboard serial ports on certain AMD motherboards have an invalid _STA
* method that always returns 0. Force them to always be treated as present.
*
* This may solely be a quirk of a preproduction BIOS.
*/
if (acpi_MatchHid(h, "AMDI0020") || acpi_MatchHid(h, "AMDI0010"))
return (TRUE);
/* If no _STA method, must be present */
if (ACPI_FAILURE(status))
return (status == AE_NOT_FOUND ? TRUE : FALSE);

View File

@ -56,6 +56,9 @@
#define UART_IOCTL_OFLOW 3
#define UART_IOCTL_BAUD 4
/* UART quirk flags */
#define UART_F_BUSY_DETECT 0x1
/*
* UART class & instance (=softc)
*/
@ -140,7 +143,7 @@ int uart_bus_detach(device_t dev);
int uart_bus_resume(device_t dev);
serdev_intr_t *uart_bus_ihand(device_t dev, int ipend);
int uart_bus_ipend(device_t dev);
int uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int chan);
int uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int chan, int quirks);
int uart_bus_sysdev(device_t dev);
void uart_sched_softih(struct uart_softc *, uint32_t);

View File

@ -37,17 +37,13 @@ __FBSDID("$FreeBSD$");
#include <sys/rman.h>
#include <machine/resource.h>
#include <isa/isavar.h>
#include <dev/uart/uart.h>
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_cpu_acpi.h>
#ifdef __aarch64__
#include <contrib/dev/acpica/include/acpi.h>
#include <contrib/dev/acpica/include/accommon.h>
#include <dev/acpica/acpivar.h>
#endif
static int uart_acpi_probe(device_t dev);
@ -66,59 +62,40 @@ static driver_t uart_acpi_driver = {
sizeof(struct uart_softc),
};
#if defined(__i386__) || defined(__amd64__)
static struct isa_pnp_id acpi_ns8250_ids[] = {
{0x0005d041, "Standard PC COM port"}, /* PNP0500 */
{0x0105d041, "16550A-compatible COM port"}, /* PNP0501 */
{0x0205d041, "Multiport serial device (non-intelligent 16550)"}, /* PNP0502 */
{0x1005d041, "Generic IRDA-compatible device"}, /* PNP0510 */
{0x1105d041, "Generic IRDA-compatible device"}, /* PNP0511 */
{0x04f0235c, "Wacom Tablet PC Screen"}, /* WACF004 */
{0x0ef0235c, "Wacom Tablet PC Screen 00e"}, /* WACF00e */
{0xe502aa1a, "Wacom Tablet at FuS Lifebook T"}, /* FUJ02E5 */
{0}
};
#endif
#ifdef __aarch64__
static struct uart_class *
static struct acpi_uart_compat_data *
uart_acpi_find_device(device_t dev)
{
struct acpi_uart_compat_data **cd;
struct acpi_uart_compat_data **cd, *cd_it;
ACPI_HANDLE h;
if ((h = acpi_get_handle(dev)) == NULL)
return (NULL);
SET_FOREACH(cd, uart_acpi_class_and_device_set) {
if (acpi_MatchHid(h, (*cd)->hid)) {
return ((*cd)->clas);
for (cd_it = *cd; cd_it->cd_hid != NULL; cd_it++) {
if (acpi_MatchHid(h, cd_it->cd_hid))
return (cd_it);
}
}
return (NULL);
}
#endif
static int
uart_acpi_probe(device_t dev)
{
struct uart_softc *sc;
struct acpi_uart_compat_data *cd;
sc = device_get_softc(dev);
#if defined(__i386__) || defined(__amd64__)
if (!ISA_PNP_PROBE(device_get_parent(dev), dev, acpi_ns8250_ids)) {
sc->sc_class = &uart_ns8250_class;
return (uart_bus_probe(dev, 0, 0, 0, 0, 0));
if ((cd = uart_acpi_find_device(dev)) != NULL) {
sc->sc_class = cd->cd_class;
if (cd->cd_desc != NULL)
device_set_desc(dev, cd->cd_desc);
return (uart_bus_probe(dev, cd->cd_regshft, cd->cd_regiowidth,
cd->cd_rclk, 0, 0, cd->cd_quirks));
}
/* Add checks for non-ns8250 IDs here. */
#elif defined(__aarch64__)
if ((sc->sc_class = uart_acpi_find_device(dev)) != NULL)
return (uart_bus_probe(dev, 2, 0, 0, 0, 0));
#endif
return (ENXIO);
}

View File

@ -99,7 +99,7 @@ uart_ebus_probe(device_t dev)
return (ENXIO);
}
sc->sc_class = &uart_ns8250_class;
return (uart_bus_probe(dev, 0, 0, 0, 0, 0));
return (uart_bus_probe(dev, 0, 0, 0, 0, 0, 0));
}
return (ENXIO);

View File

@ -278,7 +278,7 @@ uart_fdt_probe(device_t dev)
if (uart_fdt_get_io_width(node, &iowidth) != 0)
iowidth = uart_getregiowidth(sc->sc_class);
return (uart_bus_probe(dev, (int)shift, (int)iowidth, (int)clock, 0, 0));
return (uart_bus_probe(dev, (int)shift, (int)iowidth, (int)clock, 0, 0, 0));
}
DRIVER_MODULE(uart, simplebus, uart_fdt_driver, uart_devclass, 0, 0);

View File

@ -168,7 +168,7 @@ uart_isa_probe(device_t dev)
/* Probe PnP _and_ non-PnP ns8250 here. */
sc->sc_class = &uart_ns8250_class;
return (uart_bus_probe(dev, 0, 0, 0, 0, 0));
return (uart_bus_probe(dev, 0, 0, 0, 0, 0, 0));
}
DRIVER_MODULE(uart, isa, uart_isa_driver, uart_devclass, 0, 0);

View File

@ -95,7 +95,7 @@ uart_pccard_attach(device_t dev)
sc = device_get_softc(dev);
sc->sc_class = &uart_ns8250_class;
error = uart_bus_probe(dev, 0, 0, 0, 0, 0);
error = uart_bus_probe(dev, 0, 0, 0, 0, 0, 0);
if (error > 0)
return (error);
return (uart_bus_attach(dev));

View File

@ -206,7 +206,7 @@ uart_pci_probe(device_t dev)
return (ENXIO);
match:
result = uart_bus_probe(dev, id->regshft, 0, id->rclk, id->rid, 0);
result = uart_bus_probe(dev, id->regshft, 0, id->rclk, id->rid, 0, 0);
/* Bail out on error. */
if (result > 0)
return (result);

View File

@ -83,7 +83,7 @@ uart_puc_probe(device_t dev)
if (BUS_READ_IVAR(parent, dev, PUC_IVAR_CLOCK, &rclk))
rclk = 0;
return (uart_bus_probe(dev, 0, 0, rclk, 0, 0));
return (uart_bus_probe(dev, 0, 0, rclk, 0, 0, 0));
}
DRIVER_MODULE(uart, puc, uart_puc_driver, uart_devclass, 0, 0);

View File

@ -114,7 +114,7 @@ uart_scc_probe(device_t dev)
BUS_READ_IVAR(parent, dev, SCC_IVAR_REGSHFT, &rs))
return (ENXIO);
return (uart_bus_probe(dev, rs, 0, cl, 0, ch));
return (uart_bus_probe(dev, rs, 0, cl, 0, ch, 0));
}
DRIVER_MODULE(uart, scc, uart_scc_driver, uart_devclass, 0, 0);

View File

@ -493,7 +493,7 @@ uart_bus_sysdev(device_t dev)
}
int
uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int chan)
uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int chan, int quirks)
{
struct uart_softc *sc;
struct uart_devinfo *sysdev;
@ -553,6 +553,7 @@ uart_bus_probe(device_t dev, int regshft, int regiowidth, int rclk, int rid, int
sc->sc_bas.regshft = regshft;
sc->sc_bas.regiowidth = regiowidth;
sc->sc_bas.rclk = (rclk == 0) ? sc->sc_class->uc_rclk : rclk;
sc->sc_bas.busy_detect = !!(quirks & UART_F_BUSY_DETECT);
SLIST_FOREACH(sysdev, &uart_sysdevs, next) {
if (chan == sysdev->bas.chan &&

View File

@ -38,9 +38,15 @@
struct uart_class;
struct acpi_uart_compat_data {
const char *hid;
struct uart_class *clas;
uint16_t port_subtype;
const char *cd_hid;
struct uart_class *cd_class;
uint16_t cd_port_subtype;
int cd_regshft;
int cd_regiowidth;
int cd_rclk;
int cd_quirks;
const char *cd_desc;
};
/*

View File

@ -88,16 +88,16 @@ uart_cpu_acpi_scan(uint8_t interface_type)
SET_FOREACH(cd, uart_acpi_class_and_device_set) {
curcd = *cd;
for (i = 0; curcd[i].hid != NULL; i++) {
if (curcd[i].port_subtype == interface_type)
for (i = 0; curcd[i].cd_hid != NULL; i++) {
if (curcd[i].cd_port_subtype == interface_type)
return (&curcd[i]);
}
}
SET_FOREACH(cd, uart_acpi_class_set) {
curcd = *cd;
for (i = 0; curcd[i].hid != NULL; i++) {
if (curcd[i].port_subtype == interface_type)
for (i = 0; curcd[i].cd_hid != NULL; i++) {
if (curcd[i].cd_port_subtype == interface_type)
return (&curcd[i]);
}
}
@ -147,7 +147,7 @@ uart_cpu_acpi_probe(struct uart_class **classp, bus_space_tag_t *bst,
if (err != 0)
goto out;
*classp = cd->clas;
*classp = cd->cd_class;
*rclk = 0;
*shiftp = 2;
*iowidthp = spcr->SerialPort.BitWidth / 8;

View File

@ -26,6 +26,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_acpi.h"
#include "opt_platform.h"
#include "opt_uart.h"
@ -54,6 +55,9 @@ __FBSDID("$FreeBSD$");
#include <dev/uart/uart_bus.h>
#include <dev/uart/uart_dev_ns8250.h>
#include <dev/uart/uart_ppstypes.h>
#ifdef DEV_ACPI
#include <dev/uart/uart_cpu_acpi.h>
#endif
#include <dev/ic/ns16550.h>
@ -404,6 +408,26 @@ struct uart_class uart_ns8250_class = {
.uc_rshift = 0
};
/*
* XXX -- refactor out ACPI and FDT ifdefs
*/
#ifdef DEV_ACPI
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"},
{"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"},
{"PNP0502", &uart_ns8250_class, 0, 0, 0, 0, 0, "Multiport serial device (non-intelligent 16550)"},
{"PNP0510", &uart_ns8250_class, 0, 0, 0, 0, 0, "Generic IRDA-compatible device"},
{"PNP0511", &uart_ns8250_class, 0, 0, 0, 0, 0, "Generic IRDA-compatible device"},
{"WACF004", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet PC Screen"},
{"WACF00E", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet PC Screen 00e"},
{"FUJ02E5", &uart_ns8250_class, 0, 0, 0, 0, 0, "Wacom Tablet at FuS Lifebook T"},
{NULL, NULL, 0, 0 , 0, 0, 0, NULL},
};
UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data);
#endif
#ifdef FDT
static struct ofw_compat_data compat_data[] = {
{"ns16550", (uintptr_t)&uart_ns8250_class},

View File

@ -342,9 +342,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},
{"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC},
{NULL, NULL, 0},
{"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_PL011, 2, 0, 0, 0, "uart plo11"},
{"ARMH0011", &uart_pl011_class, ACPI_DBG2_ARM_SBSA_GENERIC, 2, 0, 0, 0, "uart plo11"},
{NULL, NULL, 0, 0, 0, 0, 0, NULL},
};
UART_ACPI_CLASS_AND_DEVICE(acpi_compat_data);
#endif

View File

@ -99,22 +99,9 @@ early_putc_t *early_putc = uart_snps_early_putc;
#endif /* EARLY_PRINTF */
#endif
static int
snps_uart_attach(struct uart_softc *uart_sc)
{
struct snps_softc *sc;
sc = (struct snps_softc *)uart_sc;
/* UART requires to read USR reg when IIR_BUSY */
uart_sc->sc_bas.busy_detect = 1;
return (ns8250_bus_attach(uart_sc));
}
static kobj_method_t snps_methods[] = {
KOBJMETHOD(uart_probe, ns8250_bus_probe),
KOBJMETHOD(uart_attach, snps_uart_attach),
KOBJMETHOD(uart_attach, ns8250_bus_attach),
KOBJMETHOD(uart_detach, ns8250_bus_detach),
KOBJMETHOD(uart_flush, ns8250_bus_flush),
KOBJMETHOD(uart_getsig, ns8250_bus_getsig),
@ -238,7 +225,7 @@ snps_probe(device_t dev)
if (bootverbose && clock == 0)
device_printf(dev, "could not determine frequency\n");
error = uart_bus_probe(dev, (int)shift, (int)iowidth, (int)clock, 0, 0);
error = uart_bus_probe(dev, (int)shift, (int)iowidth, (int)clock, 0, 0, UART_F_BUSY_DETECT);
if (error != 0)
return (error);

View File

@ -83,7 +83,7 @@ uart_ar5315_probe(device_t dev)
sc->sc_bas.bst = mips_bus_space_generic;
sc->sc_bas.bsh = ar531x_uart_addr() + 3;
return (uart_bus_probe(dev, 2, 0, freq, 0, 0));
return (uart_bus_probe(dev, 2, 0, freq, 0, 0, 0));
}
DRIVER_MODULE(uart, apb, uart_ar5315_driver, uart_devclass, 0, 0);

View File

@ -85,7 +85,7 @@ uart_ar71xx_probe(device_t dev)
sc->sc_bas.bst = mips_bus_space_generic;
sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR) + 3;
return (uart_bus_probe(dev, 2, 0, freq, 0, 0));
return (uart_bus_probe(dev, 2, 0, freq, 0, 0, 0));
}
#ifdef EARLY_PRINTF

View File

@ -90,7 +90,7 @@ uart_ar933x_probe(device_t dev)
sc->sc_bas.bst = mips_bus_space_generic;
sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR);
return (uart_bus_probe(dev, 2, 0, freq, 0, 0));
return (uart_bus_probe(dev, 2, 0, freq, 0, 0, 0));
}
/*

View File

@ -61,7 +61,7 @@ uart_chipc_probe(device_t dev)
sc->sc_class = &uart_ns8250_class;
rclk = bcm_get_uart_rclk(bcm_get_platform());
return (uart_bus_probe(dev, 0, 0, rclk, 0, 0));
return (uart_bus_probe(dev, 0, 0, rclk, 0, 0, 0));
}
static device_method_t uart_chipc_methods[] = {

View File

@ -107,7 +107,7 @@ uart_octeon_probe(device_t dev)
if (bus_space_map(sc->sc_bas.bst, CVMX_MIO_UARTX_RBR(0),
uart_getrange(sc->sc_class), 0, &sc->sc_bas.bsh) != 0)
return (ENXIO);
return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, 0, unit));
return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, 0, unit, 0));
}
DRIVER_MODULE(uart, obio, uart_octeon_driver, uart_devclass, 0, 0);

View File

@ -179,7 +179,7 @@ jz4780_uart_probe(device_t dev)
device_printf(dev, "got UART clock: %lld\n", freq);
sc->ns8250_base.base.sc_class = (struct uart_class *)cd->ocd_data;
shift = jz4780_uart_get_shift(dev);
return (uart_bus_probe(dev, shift, 0, (int)freq, 0, 0));
return (uart_bus_probe(dev, shift, 0, (int)freq, 0, 0, 0));
}
static int

View File

@ -87,7 +87,7 @@ uart_malta_probe(device_t dev)
sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
sc->sc_bas.bst = mips_bus_space_generic;
sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
return(uart_bus_probe(dev, 0, 0, 0, 0, 0));
return(uart_bus_probe(dev, 0, 0, 0, 0, 0, 0));
}
DRIVER_MODULE(uart, obio, uart_malta_driver, uart_devclass, 0, 0);

View File

@ -2,6 +2,11 @@
.PATH: ${SRCTOP}/sys/dev/uart
.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "amd64" || \
${MACHINE_CPUARCH} == "i386"
uart_bus_acpi=uart_bus_acpi.c
.endif
.if ${MACHINE_CPUARCH} == "sparc64"
uart_bus_ebus= uart_bus_ebus.c
.endif
@ -27,7 +32,7 @@ uart_dev_mu=uart_dev_mu.c
.endif
KMOD= uart
SRCS= uart_bus_acpi.c ${uart_bus_ebus} uart_bus_isa.c uart_bus_pccard.c \
SRCS= ${uart_bus_acpi} ${uart_bus_ebus} uart_bus_isa.c uart_bus_pccard.c \
uart_bus_pci.c uart_bus_puc.c uart_bus_scc.c \
uart_core.c ${uart_cpu_machine} uart_dbg.c \
${uart_dev_mvebu} uart_dev_ns8250.c ${uart_dev_mu} \
@ -37,6 +42,6 @@ SRCS= uart_bus_acpi.c ${uart_bus_ebus} uart_bus_isa.c uart_bus_pccard.c \
SRCS+= acpi_if.h bus_if.h card_if.h device_if.h isa_if.h ${ofw_bus_if} \
pci_if.h \
power_if.h pccarddevs.h serdev_if.h
SRCS+= opt_platform.h opt_uart.h
SRCS+= opt_acpi.h opt_platform.h opt_uart.h
.include <bsd.kmod.mk>

View File

@ -83,7 +83,7 @@ uart_iobus_probe(device_t dev)
sc->sc_class = &uart_ns8250_class;
device_set_desc(dev, "PSIM serial port");
return (uart_bus_probe(dev, 0, 0, 0, 0, 0));
return (uart_bus_probe(dev, 0, 0, 0, 0, 0, 0));
}
DRIVER_MODULE(uart, iobus, uart_iobus_driver, uart_devclass, 0, 0);

View File

@ -620,7 +620,7 @@ sbbc_uart_sbbc_probe(device_t dev)
sc = device_get_softc(dev);
sc->sc_class = &uart_sbbc_class;
device_set_desc(dev, "Serengeti console");
return (uart_bus_probe(dev, 0, 0, 0, SBBC_PCI_BAR, 0));
return (uart_bus_probe(dev, 0, 0, 0, SBBC_PCI_BAR, 0, 0));
}
/*