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.

Remoteproc/IPU doesn't suspend

Other Parts Discussed in Thread: 4460

Hi!

I go forward with my personal project, where I try to move from a working 3.0 kernel to 3.4 kernel.
I have a custom board, archos g9 series with omap 4460 chip and 1Gbyte of RAM.

Due the fact that I want to use the camera driver and the OMX components, I have to use the ducati-m3.bin firmware binary from the vendor,
I can't use the remoteproc/rpmsg implementation of the 3.4 series (and up).
So I forward-ported this components into this 3.4 tree. (Mainly the iommu access needs to modified). I have some success:

  • HD video working

  • Camera drivers working

Currently an issue is the suspend mode. It seems that the processor doesn't enters the power saving mode.

In file omap_remoteproc.c there is the function _suspend which is called, in case the remoteproc should be switched the power mode.

static int _suspend(struct omap_rproc_priv *rpp, bool force)
{
unsigned long timeout = msecs_to_jiffies(PM_SUSPEND_TIMEOUT) + jiffies;
if (force)
omap_mbox_msg_send(rpp->mbox, PM_SUSPEND_MBOX_FORCE);
else
omap_mbox_msg_send(rpp->mbox, PM_SUSPEND_MBOX);
while (time_after(timeout, jiffies)) {
if ((readl(rpp->suspend) & rpp->suspend_mask) &&
(readl(rpp->idle) & rpp->idle_mask))
return 0;
schedule();
}
return -EAGAIN;
}

Within the while loop, there are checked continuously the suspend and idle adress.
Both seems to not match the idle/suspend mask. (More detail: suspend value is always 0, where idle value contains some value, I'm not sure If they match the mask, since the suspend value has first priority).

I don't have any glue, how to solve the problem :-(.
Maybe someone can give some hints how I can be sure, that the mailbox delivers the PM_SUSPEND_MBOX/PM_SUSPEND_MBOX_FORCE request.
Is there an way to identify that the remoteproc received this event and has processed it?
Another case is, that the remoteproc is busy all the time, but how can I see what they is doing?

Thanks :-)

  • Hi!

    I have some additional informations about the current state. I re-read my logs and find out, that the starting sequence is like:

    1. omap_rproc_activate()
    2. _suspend()
      [   30.313262] >>drivers/remoteproc/omap_remoteproc.c:_suspend:98: Last read suspend state: Suspend Address: 0xf03dc2d8 - Value: 0x1 Idle Address: 0xf03da920 - Value: 0x40001.
    3. omap_rproc_deactivate()
    4. omap_rproc_activate()

    So I was wrong! The IPU seems to be in suspended mode already (Which is good!). But how I can wake up them from this state?
    It seems it this late riser is sleeping forever....
    Update: The dd IPU seems to sleep well, see next post.

    In the Document Design_Overview_-_RPMsg there is a hint: "[..]The resume process would simply release the reset of the remote processors[..]", but how to achive that?
    The omap_hwmod_enable(od->hwmods[i]); seems to not to do the job. But should they?
    Maybe someone has some hints for me ;)

    Currently my omap_rproc_activate() method looks like this:

    int omap_rproc_activate(struct omap_device *od)
    {
        int i, ret = 0;
        struct rproc *rproc = platform_get_drvdata(od->pdev);
        struct device *dev = rproc->dev;
        struct omap_rproc_pdata *pdata = dev->platform_data;
        struct omap_rproc_timers_info *timers = pdata->timers;
        struct omap_rproc_priv *rpp = rproc->priv;

    #ifdef CONFIG_REMOTEPROC_AUTOSUSPEND
        //Try to ise activate/deactivate like the 3.4 way
        rproc_activate_iommu(rpp);

        if (!rpp->mbox)
            rpp->mbox = omap_mbox_get(pdata->sus_mbox_name, NULL);
    #endif
        /**
         * explicitly configure a boot address from which remoteproc
         * starts executing code when taken out of reset.
         */
        _load_boot_addr(rproc, rpp->bootaddr);

        /**
         * Domain is in HW SUP thus in hw_auto but
         * since remoteproc will be enabled clkdm
         * needs to be in sw_sup (Do not let it idle).
         */
        if (pdata->clkdm)
            clkdm_wakeup(pdata->clkdm);

        for (i = 0; i < pdata->timers_cnt; i++)
            omap_dm_timer_start(timers[i].odt);

        for (i = 0; i < od->hwmods_cnt; i++) {
            ret = omap_hwmod_enable(od->hwmods[i]);
            if (ret) {
                for (i = 0; i < pdata->timers_cnt; i++)
                    omap_dm_timer_stop(timers[i].odt);
                break;
            }
        }

        /**
         * Domain is in force_wkup but since remoteproc
         * was enabled it is safe now to switch clkdm
         * to hw_auto (let it idle).
         */
        if (pdata->clkdm)
            clkdm_allow_idle(pdata->clkdm);

        return ret;
    #ifdef CONFIG_REMOTEPROC_AUTOSUSPEND
    free_domain:
        if (rpp->domain){
            iommu_domain_free(rpp->domain);
        }
    err_mmu:
        if (pdata->clkdm)
            clkdm_allow_idle(pdata->clkdm);
        kfree(rpp);
    #endif
        return ret;
    }

    This is pretty much the same as the 3.0 kernel series provides. However I remove the IOMMU removal, and replaced them with
    a call of rproc_activate_iommu(rpp) which points to:

    static void rproc_activate_iommu(struct omap_rproc_priv *rpp)
    {
        struct iommu_domain *domain = rpp->domain;
        if (domain)
            iommu_domain_activate(domain);
    }

    Now the opposite, omap_deactivate_rproc:

    int omap_rproc_deactivate(struct omap_device *od)
    {
        int i, ret = 0;
        struct rproc *rproc = platform_get_drvdata(od->pdev);
        struct device *dev = rproc->dev;
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_rproc_pdata *pdata = dev->platform_data;
        struct omap_rproc_timers_info *timers = pdata->timers;

    #ifdef CONFIG_REMOTEPROC_AUTOSUSPEND
        struct omap_rproc_priv *rpp = rproc->priv;
    #endif
        if (pdata->clkdm)
            clkdm_wakeup(pdata->clkdm);

        for (i = 0; i < od->hwmods_cnt; i++) {
            ret = omap_hwmod_shutdown(od->hwmods[i]);
            if (ret)
                goto err;
        }

        for (i = 0; i < pdata->timers_cnt; i++)
            omap_dm_timer_stop(timers[i].odt);

    #ifdef CONFIG_REMOTEPROC_AUTOSUSPEND
        //Try to use activate/deactivate like the 3.4 way
        rproc_idle_iommu(rpp);

        if (rpp->mbox) {
            omap_mbox_put(rpp->mbox, NULL);
            rpp->mbox = NULL;
        }

    #endif
    err:
        if (pdata->clkdm)
            clkdm_allow_idle(pdata->clkdm);

        return ret;
    }

    Also, I removed the iommu stuff and replaced them with  a call to rproc_idle_iommu():

    static void rproc_idle_iommu(struct omap_rproc_priv *rpp)
    {
        struct iommu_domain *domain = rpp->domain;
        if (domain)
            iommu_domain_idle(domain);
    }

    Thanks!

  • Hi there!

    I really should use the blog feature for my observations.
    I've done some experiments and found out, that I wasn't wrong with my first projection. It seems that the mailbox wasn't able to deliver the SUSPEND flag to the IPU.
    When I modify the function omap_deactivate_rproc:

    /*   if (rpp->mbox) {
           omap_mbox_put(rpp->mbox, NULL);

            rpp->mbox = NULL;
        }

    */

    to remove the mailbox on suspend, it seems that this fixes the trouble. But why the mailbox isn't correctly restored?
    In function omap_rproc_activate() there is the following call which should do the job (Which is the same I used on function _init_pm_flags()):

    if (!rpp->mbox)
            rpp->mbox = omap_mbox_get(pdata->sus_mbox_name, NULL);

    Any ideas?

  • I found the reason why the mailbox isn't react anymore.

    In file
    arch/arm/plat-omap/mailbox.c

    I commented out the context restore skip logic:

     static int omap_mbox_restore_ctx(struct device *dev, void *data)
     {
            struct omap_mbox *mbox = dev_get_drvdata(dev);

    //     /* mailbox is not init'ed.. no need to restore */
    //     if (!mbox->use_count){
    //             return 0;
    //     }

    Can somebody explain the original code? In my case the use_count is set to 0, because all mailboxes are "putted" on suspend.