On Wed, Nov 24, 2010 at 4:24 PM, G, Manjunath Kondaiah <manjugk@xxxxxx> wrote: > Certain errata in OMAP2+ processors will require forcing > master standby to "no standby" mode before completing on going > operation. Without this, the results will be unpredictable. > > Since current implementation of PM run time framework does not support > changing sysconfig settings during middle of the on going operation, > these API's will support the same. One API will force the device's > sysconfig mstandby mode settings to "no standby" and other API will > release "no standby" mode and sets it to "smart standby" or "no > standbyË depending on HWMOD_SWSUP_MSTANDBY value. > > These API's should be used by device drivers only incase of > erratum applicable to their modules if there is no other methods > to resolve. > > These API's are required for multiple DMA errata which require > putting DMA controller in no mstandby mode before stopping dma. > > The applicable errata: > 1. Erratum ID: i557(Applicable for omap36xx all ES versions) > The channel hangs when the Pause bit (DMA4_CDPi [7] ) is cleared > through config port while in Standby. > > 2. Erratum ID: i541 > sDMA FIFO draining does not finish. Applicable to all omap2+ except > omap4. > > 3. Erratum ID:i88 > The sDMA to be put in no mstandby mode before disabling the channel > after completing the data transfer operation. > Applicable only for OMAP3430 ES1.0 > > Also fixes typo HWMOD_SWSUP_MSTDBY to HWMOD_SWSUP_MSTANDBY in > omap_hwmod.h > > Signed-off-by: G, Manjunath Kondaiah <manjugk@xxxxxx> > Cc: Kevin Hilman <khilman@xxxxxxxxxxxxxxxxxxx> > Cc: Paul Walmsley <paul@xxxxxxxxx> > Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > --- > Change summary: > v3: Review comments incorporated for: > https://patchwork.kernel.org/patch/282212/ > v4: added mutex changes > v5: typo fixes for errata and erratum > > Âarch/arm/mach-omap2/omap_hwmod.c       Â|  43 ++++++++++++++++- > Âarch/arm/plat-omap/include/plat/omap_device.h |  Â2 + > Âarch/arm/plat-omap/include/plat/omap_hwmod.h Â|  Â4 +- > Âarch/arm/plat-omap/omap_device.c       Â|  64 +++++++++++++++++++++++++ > Â4 files changed, 111 insertions(+), 2 deletions(-) > > diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c > index 5a30658..de78441 100644 > --- a/arch/arm/mach-omap2/omap_hwmod.c > +++ b/arch/arm/mach-omap2/omap_hwmod.c > @@ -1427,6 +1427,48 @@ int omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode) > Â} > > Â/** > + * omap_hwmod_set_master_standbymode - set the hwmod's OCP mstandby mode > + * @oh: struct omap_hwmod * > + * @midlemode: flag to set mstandby to either "no standby" or "smart standby" > + * > + * Sets the IP block's OCP mstandby mode in hardware, and updates our > + * local copy. ÂIntended to be used by drivers that have some erratum > + * that requires direct manipulation of the MIDLEMODE bits. ÂReturns > + * -EINVAL if @oh is null, or passes along the return value from > + * _set_master_standbymode(). > + * > + * Any users of this function should be scrutinized carefully. > + */ > +int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode) > +{ > +    u32 v; > +    u8 sf; > +    int retval = 0; > + > +    if (!oh) > +        return -EINVAL; > + > +    if (!oh->class->sysc) > +        return -EINVAL; > + > +    v = oh->_sysc_cache; > +    sf = oh->class->sysc->sysc_flags; > + > +    if (sf & SYSC_HAS_MIDLEMODE) { > +        if (idlemode) > +            idlemode = HWMOD_IDLEMODE_NO; > +        else > +            idlemode = (oh->flags & HWMOD_SWSUP_MSTANDBY) ? > +                HWMOD_IDLEMODE_NO : HWMOD_IDLEMODE_SMART; > +    } > +    retval = _set_master_standbymode(oh, idlemode, &v); > +    if (!retval) > +        _write_sysconfig(v, oh); > + > +    return retval; > +} > + > +/** > Â* omap_hwmod_register - register a struct omap_hwmod > Â* @oh: struct omap_hwmod * > Â* > @@ -2116,4 +2158,3 @@ int omap_hwmod_for_each_by_class(const char *classname, > >    Âreturn ret; > Â} > - > diff --git a/arch/arm/plat-omap/include/plat/omap_device.h b/arch/arm/plat-omap/include/plat/omap_device.h > index 28e2d1a..4fbf7c1 100644 > --- a/arch/arm/plat-omap/include/plat/omap_device.h > +++ b/arch/arm/plat-omap/include/plat/omap_device.h > @@ -116,6 +116,8 @@ int omap_device_enable_hwmods(struct omap_device *od); > Âint omap_device_disable_clocks(struct omap_device *od); > Âint omap_device_enable_clocks(struct omap_device *od); > > +int omap_device_require_no_mstandby(struct platform_device *pdev); > +int omap_device_release_no_mstandby(struct platform_device *pdev); > > Â/* > Â* Entries should be kept in latency order ascending > diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h > index 7eaa8ed..c7ff65a 100644 > --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h > +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h > @@ -354,7 +354,7 @@ struct omap_hwmod_omap4_prcm { > Â* > Â* HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out > Â*   of idle, rather than relying on module smart-idle > - * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out > + * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and out > Â*   of standby, rather than relying on module smart-standby > Â* HWMOD_INIT_NO_RESET: don't reset this module at boot - important for > Â*   SDRAM controller, etc. > @@ -526,6 +526,8 @@ int omap_hwmod_disable_clocks(struct omap_hwmod *oh); > > Âint omap_hwmod_set_slave_idlemode(struct omap_hwmod *oh, u8 idlemode); > > +int omap_hwmod_set_master_standbymode(struct omap_hwmod *oh, u8 idlemode); > + > Âint omap_hwmod_reset(struct omap_hwmod *oh); > Âvoid omap_hwmod_ocp_barrier(struct omap_hwmod *oh); > > diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c > index abe933c..fa99551 100644 > --- a/arch/arm/plat-omap/omap_device.c > +++ b/arch/arm/plat-omap/omap_device.c > @@ -584,6 +584,70 @@ int omap_device_idle(struct platform_device *pdev) > Â} > > Â/** > + * omap_device_require_no_mstandby - set no mstandby mode of an omap_device > + * @od: struct omap_device * to idle > + * > + * Sets the IP block's OCP master standby to no mstandby mode in hardware. > + * > + * Intended to be used by drivers that have some erratum that requires direct > + * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the > + * omap_device is not currently enabled or passes along the return value > + * of omap_hwmod_set_master_standbymode(). > + */ > +int omap_device_require_no_mstandby(struct platform_device *pdev) > +{ > +    int ret Â= 0, i; > +    struct omap_device *od; > +    struct omap_hwmod *oh; > + > +    od = _find_by_pdev(pdev); > +    if (od->_state != OMAP_DEVICE_STATE_ENABLED) { > +        WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", > +          Âod->pdev.name, od->pdev.id, __func__, od->_state); > +        return -EINVAL; > +    } > + > +    oh = *od->hwmods; I Guess you are missing oh++ in the following loop. > +    for (i = 0; i < od->hwmods_cnt; i++) > +        ret = omap_hwmod_set_master_standbymode(oh, true); > + > +    return ret; > +} > + > +/** > + * omap_device_release_no_mstandby - releases no mstandby mode of an omap_device > + * @od: struct omap_device * to idle > + * > + * Release no mstandby mode and sets the master standby to either no standby or > + * smart standby in IP block's OCP in hardware depending on status of the flag > + * HWMOD_SWSUP_MSTANDBY. > + * > + * Intended to be used by drivers that have some erratum that requires direct > + * manipulation of the MSTANDBYMODE bits. Returns -EINVAL if the > + * omap_device is not currently enabled or passes along the return value > + * of omap_hwmod_set_master_standbymode(). > + */ > +int omap_device_release_no_mstandby(struct platform_device *pdev) > +{ > +    int ret Â= 0, i; > +    struct omap_device *od; > +    struct omap_hwmod *oh; > + > +    od = _find_by_pdev(pdev); > +    if (od->_state != OMAP_DEVICE_STATE_ENABLED) { > +        WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", > +          Âod->pdev.name, od->pdev.id, __func__, od->_state); > +        return -EINVAL; > +    } > + > +    oh = *od->hwmods; Same comment here. > +    for (i = 0; i < od->hwmods_cnt; i++) > +        ret = omap_hwmod_set_master_standbymode(oh, false); > + > +    return ret; > +} > + > +/** > Â* omap_device_shutdown - shut down an omap_device > Â* @od: struct omap_device * to shut down > Â* > -- > 1.7.1 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-omap" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at Âhttp://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html