• Palmer Dabbelt's avatar
    tty: sifive: Finish transmission before changing the clock · 4cbd7814
    Palmer Dabbelt authored
    SiFive's UART has a software controller clock divider that produces the
    final baud rate clock.  Whenever the clock that drives the UART is
    changed this divider must be updated accordingly, and given that these
    two events are controlled by software they cannot be done atomically.
    During the period between updating the UART's driving clock and internal
    divider the UART will transmit a different baud rate than what the user
    has configured, which will probably result in a corrupted transmission
    stream.
    
    The SiFive UART has a FIFO, but due to an issue with the programming
    interface there is no way to directly determine when the UART has
    finished transmitting.  We're essentially restricted to dead reckoning
    in order to figure that out: we can use the FIFO's TX busy register to
    figure out when the last frame has begun transmission and just delay for
    a long enough that the last frame is guaranteed to get out.
    
    As far as the actual implementation goes: I've modified the existing
    existing clock notifier function to drain both the FIFO and the shift
    register in on PRE_RATE_CHANGE.  As far as I know there is no hardware
    flow control in this UART, so there's no good way to ask the other end
    to stop transmission while we can't receive (inserting software flow
    control messages seems like a bad idea here).
    Signed-off-by: default avatarPalmer Dabbelt <palmerdabbelt@google.com>
    Tested-by: default avatarYash Shah <yash.shah@sifive.com>
    Link: https://lore.kernel.org/r/20200307042637.83728-1-palmer@dabbelt.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    4cbd7814
sifive.c 29.3 KB