aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/uart
diff options
context:
space:
mode:
authorIan Lepore <ian@FreeBSD.org>2017-03-08 18:53:32 +0000
committerIan Lepore <ian@FreeBSD.org>2017-03-08 18:53:32 +0000
commit2cb357c5cd2ba914dcffcd1fa4301beff2356125 (patch)
tree94079d80c138c6aa627e60b10676dcfcb5e75ea8 /sys/dev/uart
parent696f00b67f7ef6fd26ff34f72eddefad29304637 (diff)
downloadsrc-2cb357c5cd2ba914dcffcd1fa4301beff2356125.tar.gz
src-2cb357c5cd2ba914dcffcd1fa4301beff2356125.zip
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.
Notes
Notes: svn path=/head/; revision=314917
Diffstat (limited to 'sys/dev/uart')
-rw-r--r--sys/dev/uart/uart_dev_pl011.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/sys/dev/uart/uart_dev_pl011.c b/sys/dev/uart/uart_dev_pl011.c
index 25ff57a1e4fd..eb8889976d0e 100644
--- a/sys/dev/uart/uart_dev_pl011.c
+++ b/sys/dev/uart/uart_dev_pl011.c
@@ -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 *sc, int baudrate, int databits,
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);
}