CPM2 SCC/SMC break handling broken

Laurent Pinchart laurent.pinchart at tbox.biz
Tue Oct 31 02:23:51 EST 2006


Hi Ricardo,

> > > > I need to generate a break on a CPM2 SMC serial port (same issue with
> > > > SCC serial ports).
> > > >
> > > > The tcsendbreak() man page states that the function should generate a
> > > > break between 250ms and 500ms, but testing showed that the break is
> > > > one character long (10 bits in 8N1 mode).
> > >
> > > [snip]
> > >
> > > > CPM_CR_STOP_TX is documented to generate a break of BRKCR characters.
> > > > The BRKCR register is initialized to 1, so only 1 break character is
> > > > sent, which won't last between 250ms and 500ms.
> > >
> > > [snip]
> > >
> > > > Could anyone think of a proper solution which would not disturb the
> > > > other drivers too much ?
> > >
> > > Well, one could always set the BRKCR parameter to the maximum number of
> > > break characters permitted by it's size, since the break condition will
> > > anyway end as soon as the RESTART TX command is issued as a consequence
> > > of the tty->driver->break_ctl(tty, 0) call. But I did not test this.
> >
> > That's a very good idea, but the documentation is a bit misleading here.
> > I tested the CPM2 behaviour, and found out that the break will last BRKCR
> > characters, even if a RESTART TX command is sent sooner.
> >
> > The user manual states
> >
> > "The SMC sends a programmable number of break characters according to
> > BRKCR and reverts to idle or sends data if a RESTART TRANSMIT is issued
> > before completion."
> >
> > I suppose they meant that, if a RESTART TX command is issued before
> > completion of the break sequence, the SMC will send data at the end of
> > the break sequence. This is at least the behaviour I noticed after trying
> > your idea.
>
> Too bad.... :( One more good idea to the junk bin.
>
> Hmm, just a wild shot you can try, while you're at that: what about setting
> BRKCR to zero and issuing another STOP TRANSMIT, just before the RESTART
> TRANSMIT?

Wow, congratulations. I wouldn't have thought about that.

static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
{
        struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
        int line = pinfo - cpm_uart_ports;
        volatile u16 *brkcr = IS_SMC(pinfo) ? &pinfo->smcup->smc_brkcr
                                : &pinfo->sccup->scc_brkcr;

        pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
                break_state);

        if (break_state)
        {
                *brkcr = 32767;
                cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
        }
        else
        {
                *brkcr = 0;
                cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
                cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
        }
}

This is a bit hackish though, but it works and doesn't require any API 
modification.

Vitaly, could you give me your opinion ?

> Another reasonable shot would be to disable and reenable the transmitter in
> an attempt to stop the break sequence; though I don't know what happens to
> the SMC state machine in this case.
>
> Too wild guesses? Well, maybe someone at Freescale can have a better idea.
> :)

I could try contacting them, but they will probably tell me that I should just 
set BRKCR to the number of characters I want to send. I doubt they will care 
that the kernel break handling code doesn't allow us to do that easily.

Thanks for your help.

Best regards,

Laurent Pinchart



More information about the Linuxppc-embedded mailing list