svn commit: r314917 - head/sys/dev/uart
Ian Lepore
ian at FreeBSD.org
Wed Mar 8 18:53:33 UTC 2017
Author: ian
Date: Wed Mar 8 18:53:32 2017
New Revision: 314917
URL: https://svnweb.freebsd.org/changeset/base/314917
Log:
Handle fifo size differences between older and newer revs of pl011 hardware.
Starting with rev 5 (which is inexplicably indicated by a version number
of '3' in the Peripheral ID register), the pl011 doubled the size of the
rx and tx fifos, to 32 bytes, so read the ID register and set the size
variables in the softc accordingly.
An interesting wrinkle in this otherwise-simple concept is that the
bcm2835 SoC, used in Raspberry Pi systems among others, has the rev 5
pl011 hardware, but somehow also has the older 16-byte fifos. We check
the FDT data to see if the hardware is part of a bcm283x system and use
the smaller size if so.
Thanks to jchandra@ for pointing out that newer hardware has bigger fifos.
Modified:
head/sys/dev/uart/uart_dev_pl011.c
Modified: head/sys/dev/uart/uart_dev_pl011.c
==============================================================================
--- head/sys/dev/uart/uart_dev_pl011.c Wed Mar 8 18:52:40 2017 (r314916)
+++ head/sys/dev/uart/uart_dev_pl011.c Wed Mar 8 18:53:32 2017 (r314917)
@@ -111,16 +111,24 @@ __FBSDID("$FreeBSD$");
#define UART_MIS 0x10 /* Masked interrupt status register */
#define UART_ICR 0x11 /* Interrupt clear register */
+#define UART_PIDREG_0 0x3f8 /* Peripheral ID register 0 */
+#define UART_PIDREG_1 0x3f9 /* Peripheral ID register 1 */
+#define UART_PIDREG_2 0x3fa /* Peripheral ID register 2 */
+#define UART_PIDREG_3 0x3fb /* Peripheral ID register 3 */
+
/*
- * The hardware FIFOs are 16 bytes each. We configure them to interrupt when
- * 3/4 full/empty. For RX we set the size to the full hardware capacity so that
- * the uart core allocates enough buffer space to hold a complete fifo full of
- * incoming data. For TX, we need to limit the size to the capacity we know
- * will be available when the interrupt occurs; uart_core will feed exactly that
- * many bytes to uart_pl011_bus_transmit() which must consume them all.
+ * The hardware FIFOs are 16 bytes each on rev 2 and earlier hardware, 32 bytes
+ * on rev 3 and later. We configure them to interrupt when 3/4 full/empty. For
+ * RX we set the size to the full hardware capacity so that the uart core
+ * allocates enough buffer space to hold a complete fifo full of incoming data.
+ * For TX, we need to limit the size to the capacity we know will be available
+ * when the interrupt occurs; uart_core will feed exactly that many bytes to
+ * uart_pl011_bus_transmit() which must consume them all.
*/
-#define FIFO_RX_SIZE 16
-#define FIFO_TX_SIZE 12
+#define FIFO_RX_SIZE_R2 16
+#define FIFO_TX_SIZE_R2 12
+#define FIFO_RX_SIZE_R3 32
+#define FIFO_TX_SIZE_R3 24
#define FIFO_IFLS_BITS ((IFLS_LVL_6_8th << IFLS_RX_SHIFT) | (IFLS_LVL_2_8th))
/*
@@ -440,11 +448,32 @@ uart_pl011_bus_param(struct uart_softc *
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)");
- sc->sc_rxfifosz = FIFO_RX_SIZE;
- sc->sc_txfifosz = FIFO_TX_SIZE;
+ /*
+ * 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.
+ */
+#ifdef FDT
+ is_bcm2835 = ofw_bus_is_compatible(sc->sc_dev, "brcm,bcm2835-pl011") ||
+ ofw_bus_is_compatible(sc->sc_dev, "broadcom,bcm2835-uart");
+#else
+ is_bcm2835 = false;
+#endif
+ hwrev = __uart_getreg(&sc->sc_bas, UART_PIDREG_2) >> 4;
+ if (hwrev <= 2 || is_bcm2835) {
+ sc->sc_rxfifosz = FIFO_RX_SIZE_R2;
+ sc->sc_txfifosz = FIFO_TX_SIZE_R2;
+ } else {
+ sc->sc_rxfifosz = FIFO_RX_SIZE_R3;
+ sc->sc_txfifosz = FIFO_TX_SIZE_R3;
+ }
return (0);
}
More information about the svn-src-head
mailing list