This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

UART driver( OMAP Serial ) does not generate interrupts on subsequent unload/load



Hi

We are using AM335x as a part of our product( SDK version is 7 ). I am facing an issue with the serial OMAP driver. The issue is specific to serial driver but I have to give out the below explanation to describe what we are trying to achieve( Apologize for the long description ).

We need to use either of our own custom driver in addition or OMAP serial driver for one of the UART ports ( UART 1 ) depending on the device status. I have done modifications to the am335x dts file to be able to load our driver and the OMAP serial driver using rmmod/insmod.

I built the OMAP driver as a new module and slightly modified it so that it doesn't interfere with the pre-existing OMAP driver used for other serial ports. Following is my patch for the OMAP driver:

--- /home/user/work/Apr10/diff/oldfile/omap-serial.c
+++ /home/user/work/Apr10/diff/newfile/omap-serial-alctpi.c
@@ -104,6 +104,8 @@

#define OMAP_UART_TCR_TRIG 0x0F

+#define TPI_DRIVER_NAME "omap_uart_tpi"
+
struct uart_omap_dma {
u8 uart_dma_tx;
u8 uart_dma_rx;
@@ -539,9 +541,18 @@
unsigned int type;
irqreturn_t ret = IRQ_NONE;
int max_count = 256;
+ unsigned int ier;

spin_lock(&up->port.lock);
pm_runtime_get_sync(up->dev);
+
+ /* Experimental
+ * Read IER register
+ */
+ ier = serial_in(up, UART_IER);
+ dev_printk(KERN_INFO, up->port.dev,
+ "###serial_omap_irq_1a - IER read value### - %d",
+ ier); //Manbir

do {
iir = serial_in(up, UART_IIR);
@@ -690,6 +701,7 @@
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned long flags = 0;
int retval;
+ unsigned int ier;

/*
* Allocate the IRQ
@@ -739,6 +751,14 @@
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
serial_out(up, UART_IER, up->ier);
+
+ /* Experimental
+ * Read IER register
+ */
+ ier = serial_in(up, UART_IER);
+ dev_printk(KERN_INFO, up->port.dev,
+ "###serial_omap_startup - IER read value### - %d",
+ ier); //Manbir

/* Enable module level wake up */
up->wer = OMAP_UART_WER_MOD_WKUP;
@@ -1416,7 +1436,7 @@

static struct uart_driver serial_omap_reg = {
.owner = THIS_MODULE,
- .driver_name = "OMAP-SERIAL",
+ .driver_name = "OMAP-SERIAL-TPI",
.dev_name = OMAP_SERIAL_NAME,
.nr = OMAP_MAX_HSUART_PORTS,
.cons = OMAP_CONSOLE,
@@ -1558,7 +1578,7 @@
/* check for tx enable gpio */
up->rts_gpio = of_get_named_gpio_flags(np, "rts-gpio", 0, &flags);
if (gpio_is_valid(up->rts_gpio)) {
- ret = gpio_request(up->rts_gpio, "omap-serial");
+ ret = gpio_request(up->rts_gpio, "omap_uart_tpi");
if (ret < 0)
return ret;
ret = gpio_direction_output(up->rts_gpio,
@@ -1615,7 +1635,7 @@

if (gpio_is_valid(omap_up_info->DTR_gpio) &&
omap_up_info->DTR_present) {
- ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+ ret = gpio_request(omap_up_info->DTR_gpio, "omap_uart_tpi");
if (ret < 0)
return ret;
ret = gpio_direction_output(omap_up_info->DTR_gpio,
@@ -1728,7 +1748,18 @@
{
struct uart_omap_port *up = platform_get_drvdata(dev);

- pm_runtime_put_sync(up->dev);
+ // cancel any work in the workqueue and destroy it
+ cancel_work_sync(&up->qos_work);
+ destroy_workqueue(serial_omap_uart_wq);

+ // if RS485 was enabled for this port, de-assert and free the RTS GPIO pin
+ if ((up->rs485.flags & SER_RS485_ENABLED) && gpio_is_valid(up->rts_gpio))
+ {
+ gpio_set_value(up->rts_gpio, 0);
+ gpio_free(up->rts_gpio);
+ }

+ pm_runtime_put_sync(up->dev);
pm_runtime_disable(up->dev);
uart_remove_one_port(&serial_omap_reg, &up->port);
pm_qos_remove_request(&up->pm_qos_request);
@@ -1868,9 +1899,9 @@

#if defined(CONFIG_OF)
static const struct of_device_id omap_serial_of_match[] = {
- { .compatible = "ti,omap2-uart" },
- { .compatible = "ti,omap3-uart" },
- { .compatible = "ti,omap4-uart" },
+ { .compatible = "ti,omap3-uart-tpi" },
+ {},
+ {},
{},
};
MODULE_DEVICE_TABLE(of, omap_serial_of_match);
@@ -1880,7 +1911,7 @@
.probe = serial_omap_probe,
.remove = serial_omap_remove,
.driver = {
- .name = DRIVER_NAME,
+ .name = TPI_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
.of_match_table = of_match_ptr(omap_serial_of_match),
},

Here is what i am trying to do:

The modified OMAP driver loads immediately after board start up. It works fine ( both TX/RX work on UART 1). I unload the driver using rmmod. I load it again insmod. On second time load of the driver only TX works and not RX. I get only one interrupt for RX and driver seems stuck there. I had to modify the driver ( basically free the GPIO pin ) to get it to this stage as well. 

I did some further analysis and found the following( though nothing points to any issue ). The below is the observation for both first time and second time loading of the driver. 

root@router:~# cat /sys/kernel/debug/gpio 
GPIOs 0-31, gpio:
....
gpio-13 (omap_uart_tpi ) out lo
....

GPIOs 32-63, gpio:
...

GPIOs 64-95, gpio:
....
gpio-81 (omap_uart_cmnet ) out lo
gpio-91 (omap-serial ) out lo
gpio-93 (omap-serial ) out lo

....

So the GPIO is in correct state both the times the driver is loaded. Following is the UART description:

root@router:~# cat /proc/tty/driver/OMAP-SERIAL-TPI 
serinfo:1.0 driver revision:
1: uart:OMAP UART1 mmio:0x48022000 irq:89 tx:0 rx:1 RTS|CTS|DTR|DSR|CD|RI

THE IRQ and UART base region etc are correct as well. In my above patch I print the contents of the IER UART register for debugging. Both the cases show value as 5 so this seems correct as well.

The issue is faced when I load the driver second time. It triggers interrupts only once and seems stuck there though the UART does physically receive data as measured by an RS485 COM probe. Could you give me a few hints as to what I should be checking to ensure UART was set to correct initialized state when the driver was loaded the second time?

Apologies once again for the long description. I am not a UART expert. If you need any more information, I would be happy tor provide. 

Please feel free to suggest anything.

Thanks and Regards

Manbir Singh Jhawer

  • Hi Manbir,

    I will forward this to the SW team.

  • Hi Manbir, 

    Manbir Jhawer said:
    I unload the driver using rmmod. I load it again insmod

     

    Are there any messages on your debug console, when you insmode the driver? 

    After rmmod, what is the value of conf_uart1_rxd (at 0x44E10980), is it still in muxmode  0 ? 

    Best Regards, 

    Yordan

  • Hi Yordan
    Thanks for your reply. I traced down this issue to wakeup/power management.
    As per the AM335x Sitara processors TRM, Section 19.1.4 wakeup is not supported on UART's 1-5. The one interrupt I seemed to be getting on UART 1 RX as per my previous description was from Section 19.3.5.2 i.e. Wake-up interrupt. I was getting an interrupt but IIR register wasn't being set.
    So it means that the OMAP serial driver is not fully as per TI TRM. The following changes solve my purpose( pardon the line numbers, they aren't correct in the diff below ):
    @@ -1403,7 +1517,7 @@ .shutdown = serial_omap_shutdown,
    .set_termios = serial_omap_set_termios, .pm = serial_omap_pm,
    - .set_wake = serial_omap_set_wake,+ //.set_wake = serial_omap_set_wake,
    .type = serial_omap_type, .release_port = serial_omap_release_port,
    .request_port = serial_omap_request_port,@@ -1689,10 +1841,12 @@
    serial_omap_uart_wq = create_singlethread_workqueue(up->name);
    INIT_WORK(&up->qos_work, serial_omap_uart_qos_work);
    platform_set_drvdata(pdev, up);
    if (omap_up_info->autosuspend_timeout == 0)
    omap_up_info->autosuspend_timeout = -1;
    - device_init_wakeup(up->dev, true);+ //device_init_wakeup(up->dev, true);
    + device_init_wakeup(up->dev, false); //Manbir
    We would appreciate your thought on this. Can you validate if this is correct?
    Btw, how should I read the value of conf_uart1_rxd (at 0x44E10980)?
    Thanks and RegardsManbir Singh Jhawer
  • Hi Manbir,

    Manbir Jhawer said:
    As per the AM335x Sitara processors TRM, Section 19.1.4 wakeup is not supported on UART's 1-5

    You are right, this is confirmed later in Section 19.2.1 UART Connectivity Attributes.  

    Manbir Jhawer said:
    We would appreciate your thought on this. Can you validate if this is correct?

    I will check this against latest serial driver in kernel 3.14 (TI release).  There have been changes since SDK7. 

    As for reading the value of conf_uart1_rxd, you can either use the __raw_readl() function in kernel space (have in mind that you need to ioremap() the register address), or you can use devmem2 tool in user space. 

    Best Regards, 
    Yordan