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>