Re: [PATCH v2 3/6] serial: imx: remove CTSC and CTS handling

From: Martyn Welch
Date: Fri Sep 15 2017 - 16:57:47 EST


Hi

On Wed, Jul 05, 2017 at 03:38:45PM +0200, Uwe Kleine-König wrote:
> Cc += Clemens Gruber + Fabio Estevam
>
> On Wed, Jul 05, 2017 at 03:07:03PM +0200, Romain Perier wrote:
> > From: Nandor Han <nandor.han@xxxxxx>
> >
> > CTSC and CTS are not related to DMA and might add
> > disruption in some cases.
> >
> > Signed-off-by: Romain Perier <romain.perier@xxxxxxxxxxxxx>
>
> If it was Nandor Han who created this patch, it would be great to get
> his sob. If it was you, drop the From: line above.
>

This patch was broken out from a larger one written by Nandor, who is
happy for me to add his sob.

> > ---
> > drivers/tty/serial/imx.c | 5 -----
> > 1 file changed, 5 deletions(-)
> >
> > diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> > index 5291b86..dd3ebb4 100644
> > --- a/drivers/tty/serial/imx.c
> > +++ b/drivers/tty/serial/imx.c
> > @@ -1249,11 +1249,6 @@ static void imx_disable_dma(struct imx_port *sport)
> > imx_stop_rx_dma(sport);
> > imx_stop_tx_dma(sport);
> >
> > - /* clear UCR2 */
> > - temp = readl(sport->port.membase + UCR2);
> > - temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN);
> > - writel(temp, sport->port.membase + UCR2);
> > -
>
> Before this patch imx_disable_dma resulted in the #CTS pin being high
> (inactive).
>
> Does this qualify as a fix? If so, you should sort this patch to the
> beginning of the series. Did you do test this patch and its effects
> separately?
>

I've been giving the RTS/CTS lines a bit of a kick with (and without) this
patch and I'm seeing what I'd expect to see on the CTS pin (the Wandboard
I'm using runs this in DCE mode even though it really should be in DTE
mode, hey ho). Using a little test app I've found/modified (listed below),
the CTS line can be (de)asserted whilst the device is open and the line
gets deasserted when the device closes. I have tested this port both when
acting as a console (and thus with DMA turned off) and when not used as a
console, with DMA enabled (confirmed with existing debug in driver).

This matches the behaviour of a FTDI based debug board that I've also
tried (in this case I looked at the RTS line as the device is running as a
DTE).

On my PC the same test app sets the RTS line (the serial port running as a
DTE, 8250_pnp driver) results in the CTS line being set appropriately as
well. It also stays in that state even after the serial device is closed,
this does seem right either but there you go.

With regards to the operation of the CTS/RTS line when twiddling it via
the ioctl, I think the behaviour of the IMX/FTDI is the expected one. Is
that the case?

Which I guess brings us to the lines above.

When running as an RS232 port (i.e. not rs485) the driver is using the
automatic CTSC control based on a rxFIFO watermark unless the state of the
CTS line is explictly set via an ioctl call. As such, unless I'm missing
something, the rxFIFO (and thus the automatic CTS control) is independent
of whether the DMA is running or not and thus this section looks wrong or
is at the very least in the wrong place.

Have I misunderstood something?

IIRC, the timing of DMA being enabled and disabled was changed reasonably
recently did that fix the #CTS issue possibly?

Martyn

----

Test app:

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>

static struct termios oldterminfo;


void closeserial(int fd)
{
tcsetattr(fd, TCSANOW, &oldterminfo);
if (close(fd) < 0)
perror("closeserial()");
}


int openserial(char *devicename)
{
int fd;
struct termios attr;

if ((fd = open(devicename, O_RDWR)) == -1) {
perror("openserial(): open()");
return 0;
}
if (tcgetattr(fd, &oldterminfo) == -1) {
perror("openserial(): tcgetattr()");
return 0;
}
attr = oldterminfo;
attr.c_cflag |= CRTSCTS | CLOCAL;
attr.c_oflag = 0;
if (tcflush(fd, TCIOFLUSH) == -1) {
perror("openserial(): tcflush()");
return 0;
}
if (tcsetattr(fd, TCSANOW, &attr) == -1) {
perror("initserial(): tcsetattr()");
return 0;
}
return fd;
}


int setRTS(int fd, int level)
{
int status;

if (ioctl(fd, TIOCMGET, &status) == -1) {
perror("setRTS(): TIOCMGET");
return 0;
}
if (level)
status |= TIOCM_RTS;
else
status &= ~TIOCM_RTS;
if (ioctl(fd, TIOCMSET, &status) == -1) {
perror("setRTS(): TIOCMSET");
return 0;
}
return 1;
}


int main(int argc, char *argv[])
{
int fd;
bool loop = true;
int state = 1;
int got;


fd = openserial(argv[1]);
if (!fd) {
fprintf(stderr, "Error while initializing %s.\n", argv[1]);
return 1;
}


while(loop) {
printf("Switching RTS %s\n", state ? "on" : "off");
setRTS(fd, state);

state = (++state) % 2;

got = getchar();
if (got == 'q')
break;
}
closeserial(fd);
return 0;
}