Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 8 Mar 2017 18:53:32 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r314917 - head/sys/dev/uart
Message-ID:  <201703081853.v28IrWhm099535@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703081853.v28IrWhm099535>