aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/uart/uart_dev_pl011.c
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/uart_dev_pl011.c
parent696f00b67f7ef6fd26ff34f72eddefad29304637 (diff)
Notes
Diffstat (limited to 'sys/dev/uart/uart_dev_pl011.c')
-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);
}