From 3c71015c26752b8f3fdf6ca3f61de4c941b724fb Mon Sep 17 00:00:00 2001 From: ian Date: Sat, 11 Mar 2017 22:34:02 +0000 Subject: [PATCH] Extend the pl011 small-fifos fix to other SoCs that indicate rev 5 hardware but lack the larger fifos rev 5 hardware should have. The linux world (where our FDT data comes from) solved this by adding a new property to pl011 nodes, "arm,primecell-periphid". When this property is present, its values override the values in the hardware periphid registers. For pl011 rev 5 hardware with small fifos, they override the id so that it appears to be rev 4 hardware. The driver now uses the new property when present. It also continues to check the device compat string, to handle older fdt data that may still be in use on existing systems (on RPi systems it is common to update system software without updating fdt data which is part of the boot firmware). Reviewed by: imp --- sys/dev/uart/uart_dev_pl011.c | 40 +++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c index eb8889976d0e..625b3343f17f 100644 --- a/sys/dev/uart/uart_dev_pl011.c +++ b/sys/dev/uart/uart_dev_pl011.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #ifdef FDT #include +#include #endif #include #include "uart_if.h" @@ -449,25 +450,36 @@ static int uart_pl011_bus_probe(struct uart_softc *sc) { uint8_t hwrev; - bool is_bcm2835; - - device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)"); +#ifdef FDT + pcell_t node; + uint32_t periphid; /* * The FIFO sizes vary depending on hardware; rev 2 and below have 16 - * byte FIFOs, rev 3 and up are 32 byte. We get a bit of drama, as - * always, with the bcm2835 (rpi), which claims to be rev 3, but has 16 - * byte FIFOs. We check for both the old freebsd-historic and the - * proper bindings-defined compatible strings for bcm2835. + * byte FIFOs, rev 3 and up are 32 byte. The hardware rev is in the + * primecell periphid register, but we get a bit of drama, as always, + * with the bcm2835 (rpi), which claims to be rev 3, but has 16 byte + * FIFOs. We check for both the old freebsd-historic and the proper + * bindings-defined compatible strings for bcm2835, and also check the + * workaround the linux drivers use for rpi3, which is to override the + * primecell periphid register value with a property. */ -#ifdef FDT - is_bcm2835 = ofw_bus_is_compatible(sc->sc_dev, "brcm,bcm2835-pl011") || - ofw_bus_is_compatible(sc->sc_dev, "broadcom,bcm2835-uart"); + if (ofw_bus_is_compatible(sc->sc_dev, "brcm,bcm2835-pl011") || + ofw_bus_is_compatible(sc->sc_dev, "broadcom,bcm2835-uart")) { + hwrev = 2; + } else { + node = ofw_bus_get_node(sc->sc_dev); + if (OF_getencprop(node, "arm,primecell-periphid", &periphid, + sizeof(periphid)) > 0) { + hwrev = (periphid >> 20) & 0x0f; + } else { + hwrev = __uart_getreg(&sc->sc_bas, UART_PIDREG_2) >> 4; + } + } #else - is_bcm2835 = false; -#endif hwrev = __uart_getreg(&sc->sc_bas, UART_PIDREG_2) >> 4; - if (hwrev <= 2 || is_bcm2835) { +#endif + if (hwrev <= 2) { sc->sc_rxfifosz = FIFO_RX_SIZE_R2; sc->sc_txfifosz = FIFO_TX_SIZE_R2; } else { @@ -475,6 +487,8 @@ uart_pl011_bus_probe(struct uart_softc *sc) sc->sc_txfifosz = FIFO_TX_SIZE_R3; } + device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)"); + return (0); }