OpenWrt Forum Archive

Topic: Using second Uart on AR9341 SoC

The content of this topic has been archived on 21 Apr 2018. There are no obvious gaps in this topic, but there may still be some posts missing at the end.

I tried to enable the second uart on ar9341. I had referred to this:
https://forum.openwrt.org/viewtopic.php?id=47369
and did as that article.
but failed.

root@Linkpower:~# find /sys/ -name ar9*art
/sys/devices/platform/ar933x-uart
/sys/bus/platform/devices/ar933x-uart
/sys/bus/platform/drivers/ar933x-uart
root@Linkpower:~# ls /dev
bus        mtd0       mtd3ro     mtd7       mtdblock5  ptmx       watchdog
console    mtd0ro     mtd4       mtd7ro     mtdblock6  pts        zero
full       mtd1       mtd4ro     mtdblock0  mtdblock7  random
kmsg       mtd1ro     mtd5       mtdblock1  net        shm
led4sig    mtd2       mtd5ro     mtdblock2  null       tty
log        mtd2ro     mtd6       mtdblock3  port       ttyS0
mem        mtd3       mtd6ro     mtdblock4  ppp        urandom

There is no "/dev/ttyATH0".

Are there any tips?
Thanks!

Here are some code:


#define AR71XX_APB_BASE         0x18000000
#define AR71XX_UART_SIZE        0x100
#define AR934X_UART1_BASE      (AR71XX_APB_BASE + 0x00500000)
#define AR934X_UART1_FIFO_SIZE  4

static struct resource ar933x_uart_resources[] = {
        {
                .start  = AR934X_UART1_BASE,
                .end    = AR934X_UART1_BASE + AR71XX_UART_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
        {
                .start  = ATH79_MISC_IRQ(6),
                .end    = ATH79_MISC_IRQ(6),
                .flags  = IORESOURCE_IRQ,
        },
};

static struct platform_device ar933x_uart_device = {
        .name           = DRIVER_NAME,
        .id             = -1,
        .resource       = ar933x_uart_resources,
        .num_resources  = ARRAY_SIZE(ar933x_uart_resources),
};

static void __init db120_setup(void)
{
...

    __raw_writel(0xe0000,ath79_gpio_base + 0x68);
//    __raw_writel((__raw_readl(ath79_gpio_base + 0x68) & 0xff00ffff)|0xe0000,ath79_gpio_base + 0x68);
    __raw_writel(__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_OE) & 0xffff7fff,ath79_gpio_base + AR71XX_GPIO_REG_OE);
    ath79_gpio_output_select(15, 79);

   platform_device_register(&ar933x_uart_device);
...
}

The booting log show an error as below:

[    0.680000] ar933x-uart: probe of ar933x-uart failed with error -22

We can trace the source file = linux\drivers\tty\serial\ar933x_uart.c:

static int __devinit ar933x_uart_probe(struct platform_device *pdev)
{
    struct ar933x_uart_platform_data *pdata;
    struct ar933x_uart_port *up;
    struct uart_port *port;
    struct resource *mem_res;
    struct resource *irq_res;
    unsigned int baud;
    int id;
    int ret;

    pdata = pdev->dev.platform_data;
    if (!pdata)
        return -EINVAL;
....

Obviously,  platform_device.dev should be assigned!
static struct platform_device ar933x_uart_device = {
        .name           = DRIVER_NAME,
        .id             = -1,
        .resource       = ar933x_uart_resources,
        .num_resources  = ARRAY_SIZE(ar933x_uart_resources),
    .dev        = ??????

};

But how to assign the "struct device    dev;"?

leaf_ee wrote:

Obviously,  platform_device.dev should be assigned!
static struct platform_device ar933x_uart_device = {
        .name           = DRIVER_NAME,
        .id             = -1,
        .resource       = ar933x_uart_resources,
        .num_resources  = ARRAY_SIZE(ar933x_uart_resources),
    .dev        = ??????

};

But how to assign the "struct device    dev;"?

What do you want ??

Add another serial, or
change to /use UART1 ??, this is what you've have done

The next thing you must know is thus UART 8250/16550 compatible

The AR9341 SoC does have a AR9330 and a 8250 style UART, which is normally the console.
In openwrt 12.09, AR9330-style uart is not enabled in default. I want to add AR9330-style uart as second UART. I think , The platform_device driver of  AR9330-style uart in AR9341 should be the same with "linux\drivers\tty\serial\ar933x_uart.c". 
So I only need to define a platform_device of AR9330-style uart in AR9341, then register it, and all other will be automatically done. Is that right?

I assigned platform_device.dev as follow:

static struct ar933x_uart_platform_data ar933x_uart_clk = {

        .uartclk    =25000000;    /* 25MHz XO */
};

static struct platform_device ar933x_uart_device = {
        .name           = DRIVER_NAME,
        .id             = -1,
        .resource       = ar933x_uart_resources,
        .num_resources  = ARRAY_SIZE(ar933x_uart_resources),
    .dev        = {
        .platform_data = &ar933x_uart_clk,
        .id    = -1,
    }
};


Then everything seems going well.


[    0.630000] Serial: 8250/16550 driver, 1 ports, IRQ sharing disabled
[    0.660000] serial8250.0: ttyS0 at MMIO 0x18020000 (irq = 11) is a 16550A
[    0.670000] console [ttyS0] enabled, bootconsole disabled
[    0.670000] console [ttyS0] enabled, bootconsole disabled
[    0.680000] ar933x-uart: ttyATH0 at MMIO 0x18500000 (irq = 14) is a AR933X UART
....

root@Linkpower:~# find /sys/ -name ar9*art
/sys/devices/platform/ar933x-uart
/sys/bus/platform/devices/ar933x-uart
/sys/bus/platform/drivers/ar933x-uart
/sys/bus/platform/drivers/ar933x-uart/ar933x-uart
root@Linkpower:~# stty -a -F /dev/ttyATH0
speed 9600 baud;stty: /dev/ttyATH0
line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
echoctl echoke

Now "/dev/ttyATH0" is registered!!!

When I type:

echo "hello" >/dev/ttyATH0

It takes long time to return---about 30 seconds. Use Oscilloscope to watch uart tx/rx pins,no signal outputs!

There are something wrong.

I modified the "\linux-3.3.8\drivers\tty\serial\ar933x_uart.c".

Now the uart1 transmitting is OK.
But receiving data is not correct yet. When I typed a command of " cat /dev/ttyATH0 ", then I send a string, ie, "hello" from an other device to this openwrt device. This openwrt device immediately self-reboot/reset.
That is due to memory overflow? or an uninitiated data point?

Linux v3.3  is very old ..
Why the h*ll do you stuck on this ??

You have a working debug console, so it's very easy to use
printk

The problem has solved.

I had mixed the fuction of "static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)" with the new source file of "ar934x_hs_uart.c" - which uses "struct tty_port" instead of "struct tty_struct".
Just change it to the original fuction of "static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)" in  "\linux-3.3.8\drivers\tty\serial\ar933x_uart.c".

Done!

Here is the whole changes of "\linux-3.3.8\drivers\tty\serial\ar933x_uart.c" to enable ar9341 second uart.
I wish it is helpful, since it is much more simple and easy to use!

#define AR933X_UART_MAX_STEP    0x3333

#undef AR933X_UART_FIFO_SIZE
#define AR933X_UART_FIFO_SIZE        4


static void ar933x_uart_set_termios(struct uart_port *port,
                    struct ktermios *new,
                    struct ktermios *old)
{
    struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
    unsigned int cs;
    unsigned long flags;
    unsigned int baud, scale, step;

    /* Only CS8 is supported */
    new->c_cflag &= ~CSIZE;
    new->c_cflag |= CS8;

    /* Only one stop bit is supported */
    new->c_cflag &= ~CSTOPB;

    cs = 0;
    if (new->c_cflag & PARENB) {
        if (!(new->c_cflag & PARODD))
            cs |= AR933X_UART_CS_PARITY_EVEN;
        else
            cs |= AR933X_UART_CS_PARITY_ODD;
    } else {
        cs |= AR933X_UART_CS_PARITY_NONE;
    }

    /* Mark/space parity is not supported */
    new->c_cflag &= ~CMSPAR;

    baud = uart_get_baud_rate(port, new, old, up->min_baud, up->max_baud);
    ar933x_uart_get_scale_step(port->uartclk, baud, &scale, &step);

    /*
     * Ok, we're now changing the port state. Do it with
     * interrupts disabled.
     */
    spin_lock_irqsave(&up->port.lock, flags);

    /* disable the UART */
    ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
              AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S);

    /* Update the per-port timeout. */
    uart_update_timeout(port, new->c_cflag, baud);

    up->port.ignore_status_mask = 0;

    /* ignore all characters if CREAD is not set */
    if ((new->c_cflag & CREAD) == 0)
        up->port.ignore_status_mask |= AR933X_DUMMY_STATUS_RD;

    ar933x_uart_write(up, AR933X_UART_CLOCK_REG,
              scale << AR933X_UART_CLOCK_SCALE_S | step);

    /* setup configuration register */
    ar933x_uart_rmw(up, AR933X_UART_CS_REG, AR933X_UART_CS_PARITY_M, cs);

    /* enable host interrupt */
    ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
                AR933X_UART_CS_HOST_INT_EN);

    /* enable TX ready overide */

    ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_TX_READY_ORIDE);


    /* enable RX ready overide */

    ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_RX_READY_ORIDE);

    /* reenable the UART */
    ar933x_uart_rmw(up, AR933X_UART_CS_REG,
                AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
                AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);

    spin_unlock_irqrestore(&up->port.lock, flags);

    if (tty_termios_baud_rate(new))
        tty_termios_encode_baud_rate(new, baud, baud);
}


static int ar933x_uart_startup(struct uart_port *port)
{
    struct ar933x_uart_port *up = (struct ar933x_uart_port *) port;
    unsigned long flags;
    int ret;

    ret = request_irq(up->port.irq, ar933x_uart_interrupt,
              up->port.irqflags, dev_name(up->port.dev), up);
    if (ret)
        return ret;

    spin_lock_irqsave(&up->port.lock, flags);

    /* Enable HOST interrupts */
    ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
                AR933X_UART_CS_HOST_INT_EN);

    /* enable TX ready overide */

    ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
AR933X_UART_CS_TX_READY_ORIDE);



    /* Enable RX interrupts */
    up->ier = AR933X_UART_INT_RX_VALID;
    ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);

    spin_unlock_irqrestore(&up->port.lock, flags);

    return 0;
}

The discussion might have continued from here.