]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - rpmsg/rpmsg.git/commitdiff
clocksource: timer-ti-dm: Add support to handle late attach of rproc timers
authorVenkateswara Rao Mandela <venkat.mandela@ti.com>
Thu, 12 Sep 2019 17:45:12 +0000 (17:45 +0000)
committerSuman Anna <s-anna@ti.com>
Mon, 23 Sep 2019 01:46:55 +0000 (20:46 -0500)
During late attach, the dmtimers used by remote processors would already
have been configured and running. To prevent the kernel from resetting or
reconfiguring the timers,

- Set the late attach parameter if the timer is already running.
- If late attach flag is set, increment the dmtimer's usage counter
  immediately on probe and maintain this state until remoteproc starts
  the timer. This prevents kernel power management functionality from
  idling and disabling the dmtimers.
- If late attach flag is set, also prevent the dmtimer configuration
  code from modifying the dmtimer registers.

The late attach flag in the omap_dm_timer structure is cleared on timer
start to allow normal operation to resume.

Signed-off-by: Venkateswara Rao Mandela <venkat.mandela@ti.com>
Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Shravan Karthik <shravan.karthik@ti.com>
Signed-off-by: Keerthy <j-keerthy@ti.com>
drivers/clocksource/timer-ti-dm.c
include/clocksource/timer-ti-dm.h
include/linux/platform_data/dmtimer-omap.h

index d7adbc102649619bef817a522e35934d2612a111..b2b7613f7602aa3bc91a36c132c8cc17bdb07e0a 100644 (file)
@@ -94,6 +94,13 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
 
 static void omap_timer_restore_context(struct omap_dm_timer *timer)
 {
+       /*
+        * Do not restore the context during late attach. Kernel data
+        * structure is not in sync with the register settings of the timer.
+        */
+       if (timer->late_attach)
+               return;
+
        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
                                timer->context.twer);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -194,6 +201,20 @@ static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
        return ret;
 }
 
+static int omap_dm_timer_is_enabled(struct omap_dm_timer *timer)
+{
+       u32 val;
+
+       val = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+
+       /* Check if timer ST bit is set or the Counter register is loaded */
+       if (val & OMAP_TIMER_CTRL_ST ||
+           omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG))
+               return 1;
+       else
+               return 0;
+}
+
 static void omap_dm_timer_enable(struct omap_dm_timer *timer)
 {
        int c;
@@ -247,6 +268,14 @@ static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
        __omap_dm_timer_enable_posted(timer);
        omap_dm_timer_disable(timer);
 
+       /*
+        * During late attach, do not set the timer source during prepare
+        * as the timer might be clocked from a different source. It will
+        * be set properly from remoteproc.
+        */
+       if (timer->late_attach)
+               return 0;
+
        rc = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 
        return rc;
@@ -503,6 +532,16 @@ static int omap_dm_timer_start(struct omap_dm_timer *timer)
 
        /* Save the context */
        timer->context.tclr = l;
+
+       /*
+        * Now that timer has been started, call pm_runtime_put_noidle to
+        * balance the pm_runtime device usage count to the proper value as
+        * the regular case, and reset the late_attach flag.
+        */
+       if (timer->late_attach)
+               pm_runtime_put_noidle(&timer->pdev->dev);
+       timer->late_attach = 0;
+
        return 0;
 }
 
@@ -543,10 +582,18 @@ static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
                l |= OMAP_TIMER_CTRL_AR;
        else
                l &= ~OMAP_TIMER_CTRL_AR;
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
 
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+       /*
+        * If late attach is enabled, do not modify the dmtimer registers.
+        * The registers would have been configured already.
+        */
+       if (!timer->late_attach) {
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+
+               omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
+       }
+
        /* Save the context */
        timer->context.tclr = l;
        timer->context.tldr = load;
@@ -568,13 +615,21 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        if (autoreload) {
                l |= OMAP_TIMER_CTRL_AR;
-               omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
+               /*
+                * If late attach is enabled, do not modify the dmtimer
+                * registers. The registers would have been configured
+                * already.
+                */
+               if (!timer->late_attach)
+                       omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG,
+                                               load);
        } else {
                l &= ~OMAP_TIMER_CTRL_AR;
        }
        l |= OMAP_TIMER_CTRL_ST;
 
-       __omap_dm_timer_load_start(timer, l, load, timer->posted);
+       if (!timer->late_attach)
+               __omap_dm_timer_load_start(timer, l, load, timer->posted);
 
        /* Save the context */
        timer->context.tclr = l;
@@ -847,6 +902,16 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
                        goto err_get_sync;
                }
                __omap_dm_timer_init_regs(timer);
+
+               if (omap_dm_timer_is_enabled(timer))
+                       timer->late_attach = 1;
+               /*
+                * Increase the pm_runtime usage count and prevent kernel power
+                * management from idling or disabling the timer.
+                */
+               if (timer->late_attach)
+                       pm_runtime_get_noresume(dev);
+
                pm_runtime_put(dev);
        }
 
@@ -884,6 +949,12 @@ static int omap_dm_timer_remove(struct platform_device *pdev)
                if (!strcmp(dev_name(&timer->pdev->dev),
                            dev_name(&pdev->dev))) {
                        list_del(&timer->node);
+                       /*
+                        * Reset device usage counter if late_attach is still
+                        * set
+                        */
+                       if (timer->late_attach)
+                               pm_runtime_put_noidle(&timer->pdev->dev);
                        ret = 0;
                        break;
                }
@@ -905,6 +976,7 @@ const static struct omap_dm_timer_ops dmtimer_ops = {
        .free = omap_dm_timer_free,
        .enable = omap_dm_timer_enable,
        .disable = omap_dm_timer_disable,
+       .is_enabled = omap_dm_timer_is_enabled,
        .get_fclk = omap_dm_timer_get_fclk,
        .start = omap_dm_timer_start,
        .stop = omap_dm_timer_stop,
index 7d9598dc578d3d039a5fc2bd821024e425f71ed6..a2654f4f3cbcc2201ed56d20771286f532890d0f 100644 (file)
@@ -116,6 +116,7 @@ struct omap_dm_timer {
        u32 errata;
        struct platform_device *pdev;
        struct list_head node;
+       u32 late_attach;
 };
 
 int omap_dm_timer_reserve_systimer(int id);
index 757a0f9e26f9a7b6c4b1da910fac2efcee9c658a..1f6d3b038ae0e07a4319f310338d934c7a657965 100644 (file)
@@ -28,6 +28,7 @@ struct omap_dm_timer_ops {
        int     (*free)(struct omap_dm_timer *timer);
 
        void    (*enable)(struct omap_dm_timer *timer);
+       int     (*is_enabled)(struct omap_dm_timer *timer);
        void    (*disable)(struct omap_dm_timer *timer);
 
        int     (*get_irq)(struct omap_dm_timer *timer);