Hi, This enables fifo support in pluart(4). While here, I changed the attachment output to look more like com(4). Tested on my rpi3b which has a 16 byte fifo.
Comments? OK? diff --git sys/dev/ic/pluart.c sys/dev/ic/pluart.c index eaa11b6c44b..601435c0e0c 100644 --- sys/dev/ic/pluart.c +++ sys/dev/ic/pluart.c @@ -99,6 +99,13 @@ #define UART_CR_CTSE (1 << 14) /* CTS hardware flow control enable */ #define UART_CR_RTSE (1 << 15) /* RTS hardware flow control enable */ #define UART_IFLS 0x34 /* Interrupt FIFO level select register */ +#define UART_IFLS_RX_SHIFT 3 /* RX level in bits [5:3] */ +#define UART_IFLS_TX_SHIFT 0 /* TX level in bits [2:0] */ +#define UART_IFLS_1_8 0 /* FIFO 1/8 full */ +#define UART_IFLS_1_4 1 /* FIFO 1/4 full */ +#define UART_IFLS_1_2 2 /* FIFO 1/2 full */ +#define UART_IFLS_3_4 3 /* FIFO 3/4 full */ +#define UART_IFLS_7_8 4 /* FIFO 7/8 full */ #define UART_IMSC 0x38 /* Interrupt mask set/clear register */ #define UART_IMSC_RIMIM (1 << 0) #define UART_IMSC_CTSMIM (1 << 1) @@ -115,6 +122,11 @@ #define UART_MIS 0x40 /* Masked interrupt status register */ #define UART_ICR 0x44 /* Interrupt clear register */ #define UART_DMACR 0x48 /* DMA control register */ +#define UART_PID0 0xfe0 /* Peripheral identification register 0 */ +#define UART_PID1 0xfe4 /* Peripheral identification register 1 */ +#define UART_PID2 0xfe8 /* Peripheral identification register 2 */ +#define UART_PID2_REV(x) ((x) >> 4) +#define UART_PID3 0xfec /* Peripheral identification register 3 */ #define UART_SPACE 0x100 void pluartcnprobe(struct consdev *cp); @@ -150,7 +162,12 @@ struct cdevsw pluartdev = void pluart_attach_common(struct pluart_softc *sc, int console) { - int maj; + int maj, rev; + + rev = UART_PID2_REV(bus_space_read_4(sc->sc_iot, sc->sc_ioh, + UART_PID2)); + + printf(": rev %d, %d byte fifo\n", rev, rev < 3 ? 16 : 32); if (console) { /* Locate the major number. */ @@ -159,7 +176,7 @@ pluart_attach_common(struct pluart_softc *sc, int console) break; cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit); - printf(": console"); + printf("%s: console\n", sc->sc_dev.dv_xname); SET(sc->sc_hwflags, COM_HW_CONSOLE); } @@ -171,13 +188,26 @@ pluart_attach_common(struct pluart_softc *sc, int console) panic("%s: can't establish soft interrupt.", sc->sc_dev.dv_xname); - bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, (UART_IMSC_RXIM | UART_IMSC_TXIM)); + /* + * The transmit FIFO size is set to 3/4 of the actual size as interrupts + * can only be triggered when the FIFO is partially full. Once + * triggered, we know that at least this amount is available in the + * FIFO. + */ + if (rev < 3) + sc->sc_fifolen = 24; + else + sc->sc_fifolen = 12; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IFLS, + (UART_IFLS_3_4 << UART_IFLS_RX_SHIFT) | + (UART_IFLS_1_4 << UART_IFLS_TX_SHIFT)); + sc->sc_imsc = UART_IMSC_RXIM | UART_IMSC_RTIM | UART_IMSC_TXIM; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_ICR, 0x7ff); + /* Enable FIFO. */ bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H, - bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) & - ~UART_LCR_H_FEN); - - printf("\n"); + bus_space_read_4(sc->sc_iot, sc->sc_ioh, UART_LCR_H) | + UART_LCR_H_FEN); } int @@ -197,19 +227,26 @@ pluart_intr(void *arg) if (sc->sc_tty == NULL) return 0; - if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_TXIM)) + if (!ISSET(is, UART_IMSC_RXIM) && !ISSET(is, UART_IMSC_RTIM) && + !ISSET(is, UART_IMSC_TXIM)) return 0; - if (ISSET(is, UART_IMSC_TXIM) && ISSET(tp->t_state, TS_BUSY)) { - CLR(tp->t_state, TS_BUSY | TS_FLUSH); - if (sc->sc_halt > 0) - wakeup(&tp->t_outq); - (*linesw[tp->t_line].l_start)(tp); + if (ISSET(is, UART_IMSC_TXIM)) { + /* Disable transmit interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, + sc->sc_imsc & ~UART_IMSC_TXIM); + + if (ISSET(tp->t_state, TS_BUSY)) { + CLR(tp->t_state, TS_BUSY | TS_FLUSH); + if (sc->sc_halt > 0) + wakeup(&tp->t_outq); + (*linesw[tp->t_line].l_start)(tp); + } } p = sc->sc_ibufp; - while (ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFF)) { + while (!ISSET(bus_space_read_4(iot, ioh, UART_FR), UART_FR_RXFE)) { c = bus_space_read_2(iot, ioh, UART_DR); if (c & UART_DR_BE) { #ifdef DDB @@ -322,11 +359,11 @@ pluart_param(struct tty *tp, struct termios *t) void pluart_start(struct tty *tp) { + char buf[32]; /* fifo max size */ struct pluart_softc *sc = pluart_cd.cd_devs[DEVUNIT(tp->t_dev)]; bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh = sc->sc_ioh; - u_int16_t fr; - int s; + int i, n, s; s = spltty(); if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) @@ -336,11 +373,13 @@ pluart_start(struct tty *tp) goto out; SET(tp->t_state, TS_BUSY); - fr = bus_space_read_4(iot, ioh, UART_FR); - while (tp->t_outq.c_cc != 0 && ISSET(fr, UART_FR_TXFE)) { - bus_space_write_4(iot, ioh, UART_DR, getc(&tp->t_outq)); - fr = bus_space_read_4(iot, ioh, UART_FR); - } + /* Enable transmit interrupt. */ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, UART_IMSC, sc->sc_imsc); + + n = q_to_b(&tp->t_outq, buf, sc->sc_fifolen); + for (i = 0; i < n; i++) + bus_space_write_4(iot, ioh, UART_DR, buf[i]); + out: splx(s); } diff --git sys/dev/ic/pluartvar.h sys/dev/ic/pluartvar.h index 8fcbed14d5c..5181723a066 100644 --- sys/dev/ic/pluartvar.h +++ sys/dev/ic/pluartvar.h @@ -45,6 +45,7 @@ struct pluart_softc { #define COM_SW_MDMBUF 0x08 #define COM_SW_PPS 0x10 int sc_fifolen; + int sc_imsc; u_int8_t sc_initialize; u_int8_t sc_cua;