From: vwan@ti.com Date: Mon, 3 Aug 2015 21:40:27 +0000 (-0700) Subject: Add power management support to DRA7xx DSP (part 2) X-Git-Tag: 3.40.00.04_eng~1 X-Git-Url: https://git.ti.com/gitweb?p=ipc%2Fipcdev.git;a=commitdiff_plain;h=dff0ec12701321152d7014dbfe7a6f919dd656ff;ds=sidebyside Add power management support to DRA7xx DSP (part 2) This commit ties up a few loose ends that were introduced in a previous commit to add PM support for the DSP: - Add a workaround for a silicon bug in which the DSP would hang when the idle instruction is invoked while it is placed in external memory and prefetch is enabled - Remove unnecessary Swi thread and call IpcPower_suspend in Task context - Add support for DSP2 - Add a null implementation for IpcPower that is compiled in when BIOS Power module is not used. This is simply to satisfy all existing call sites that are calling into IpcPower regardless if PM is enabled. It also prevents the BIOS Power module from being unnecessarily linked in when it is not needed. A possible future enhancement would be to look into compiling out these call sites when PM is not enabled. This is towards addressing CQ SDOCM00117446. Signed-off-by: VW --- diff --git a/packages/ti/ipc/tests/Dsp_vayu.cfg b/packages/ti/ipc/tests/Dsp_vayu.cfg index a6fe8d4..f2ca003 100644 --- a/packages/ti/ipc/tests/Dsp_vayu.cfg +++ b/packages/ti/ipc/tests/Dsp_vayu.cfg @@ -71,11 +71,11 @@ var Resource = xdc.useModule('ti.ipc.remoteproc.Resource'); Resource.loadSegment = "EXT_CODE"; /* Modules used in Power Management */ -xdc.loadPackage('ti.pm'); +/*xdc.loadPackage('ti.pm'); var Power = xdc.useModule('ti.sysbios.family.c66.vayu.Power'); Power.loadSegment = "PM_DATA"; - +*/ /* Idle function that periodically flushes the unicache */ var Idle = xdc.useModule('ti.sysbios.knl.Idle'); @@ -129,12 +129,17 @@ if (Program.platformName.match(/^ti\.platforms\.evmDRA7XX\:dsp1/)) { var Deh = xdc.useModule('ti.deh.Deh'); Idle.addFunc('&ti_deh_Deh_idleBegin'); /* Must be placed before pwr mgmt */ - //TBD Idle.addFunc('&IpcPower_idle'); /* IpcPower_idle must be at the end */ + + /* Enable if power management is desired */ + /* Idle.addFunc('&IpcPower_idle'); */ /* IpcPower_idle must be at the end */ } else { myName = "DSP2"; /* Configure BIOS clock source as GPTimer6 */ timerId = 5; + + /* Enable if power management is desired */ + /* Idle.addFunc('&IpcPower_idle'); */ /* IpcPower_idle must be at the end */ } MultiProc.setConfig(myName, ["HOST", "IPU2", "IPU1", "DSP2", "DSP1"]); @@ -153,6 +158,7 @@ Timer.checkFrequency = false; Timer.intFreq.hi = 0; Timer.intFreq.lo = 19200000; + var timerParams = new Timer.Params(); timerParams.period = Clock.tickPeriod; timerParams.periodType = Timer.PeriodType_MICROSECS; @@ -167,6 +173,16 @@ Timer.create(Clock.timerId, Clock.doTick, timerParams); Program.sectMap[".tracebuf"] = "TRACE_BUF"; Program.sectMap[".errorbuf"] = "EXC_DATA"; +/* + * Workaround for silicon bug - enable if power management is desired + * + * IpcPower_callIdle must be placed in L2SRAM and not external memory + * to avoid CPU hang when going into idle + */ +/* Resource.customTable = true; +Program.sectMap[".text:IpcPower_callIdle"] = "L2SRAM"; +*/ + /* Version module */ /* ??? xdc.useModule('ti.utils.Version'); diff --git a/packages/ti/pm/IpcPowerDsp_dra7xx.c b/packages/ti/pm/IpcPowerDsp_dra7xx.c index 5b9f7a3..5d28110 100644 --- a/packages/ti/pm/IpcPowerDsp_dra7xx.c +++ b/packages/ti/pm/IpcPowerDsp_dra7xx.c @@ -38,7 +38,6 @@ */ #include -#include #include #include #include @@ -48,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -62,10 +60,10 @@ #define IDLE_STBY_MASK 0x0000003C #define PDCCMD_REG 0x01810000 -#define SLEEP_MODE 0x10000 +#define SLEEP_MASK 0x10000 +#define AWAKE_MASK 0xFFFEFFFF static UInt32 IpcPower_hibLock; -static Swi_Handle suspendResumeSwi; static Semaphore_Handle IpcPower_semSuspend = NULL; static Semaphore_Handle IpcPower_semExit = NULL; static Task_Handle IpcPower_tskSuspend = NULL; @@ -83,9 +81,6 @@ typedef enum IpcPower_SleepMode { IpcPower_SLEEP_MODE_WAKEUNLOCK } IpcPower_SleepMode; -/* Deep sleep state variable for IpcPower module */ -static Bool IpcPower_deepSleep = TRUE; - static IpcPower_WugenEvtMask wugenEvtMask; /* PM transition debug counters */ @@ -96,6 +91,12 @@ UInt32 IpcPower_resumeCount = 0; /* Handle to store BIOS Tick Timer */ static Timer_Handle tickTimerHandle = NULL; +/* + * Assembly function that calls idle using a workaround for a silicon bug that + * would hang the CPU when prefetch is enabled. + */ +extern Void IpcPower_callIdle(); + /* * ======== IpcPower_callUserFxns ======== */ @@ -126,12 +127,14 @@ static inline Void IpcPower_sleepMode(IpcPower_SleepMode opt) /* Fall through: */ case IpcPower_SLEEP_MODE_DEEPSLEEP: if (!refWakeLockCnt) { - IpcPower_deepSleep = TRUE; + REG32(PDCCMD_REG) |= SLEEP_MASK; + REG32(PDCCMD_REG); } break; case IpcPower_SLEEP_MODE_WAKELOCK: refWakeLockCnt++; - IpcPower_deepSleep = FALSE; + REG32(PDCCMD_REG) &= AWAKE_MASK; + REG32(PDCCMD_REG); break; } Hwi_restore(hwiKey); @@ -173,24 +176,6 @@ static inline Void IpcPower_setWugen(IpcPower_WugenEvtMask *mask) REG32(DSP_SYS_IRQWAKEEN1) |= mask->mevt1; } - -/* - * ======== IpcPower_suspendSwi ======== - */ -#define FXNN "IpcPower_suspendSwi" -static Void IpcPower_suspendSwi(UArg arg0, UArg arg1) -{ - if (refWakeLockCnt) { - Log_print0(Diags_INFO, FXNN":Warning: Wake locks in use\n"); - } - - /* Invoke the BIOS suspend routine */ - Power_suspend(Power_Suspend_HIBERNATE); - - Log_print0(Diags_INFO, FXNN":Resume\n"); -} -#undef FXNN - /* * ======== IpcPower_suspendTaskFxn ======== */ @@ -204,7 +189,7 @@ Void IpcPower_suspendTaskFxn(UArg arg0, UArg arg1) /* Call pre-suspend preparation function */ IpcPower_preSuspend(); - Swi_post(suspendResumeSwi); + Power_suspend(Power_Suspend_HIBERNATE); /* Call post-resume preparation function */ IpcPower_postResume(); @@ -218,9 +203,10 @@ Void IpcPower_suspendTaskFxn(UArg arg0, UArg arg1) /* * ======== IpcPower_init ======== */ +#define FXNN "IpcPower_init" Void IpcPower_init() { - Swi_Params swiParams; + extern cregister volatile UInt DNUM; Task_Params taskParams; Int i; UArg arg; @@ -244,8 +230,9 @@ Void IpcPower_init() } } if (tickTimerHandle == NULL) { - System_abort("IpcPower_init: Cannot find tickTimer Handle. Custom" - " clock timer functions currently not supported.\n"); + Log_print0(Diags_INFO, FXNN": Cannot find tickTimer Handle. " + "Custom clock timer functions currently not " + "supported.\n"); } IpcPower_semSuspend = Semaphore_create(0, NULL, NULL); @@ -257,10 +244,6 @@ Void IpcPower_init() IpcPower_tskSuspend = Task_create(IpcPower_suspendTaskFxn, &taskParams, NULL); - Swi_Params_init(&swiParams); - swiParams.priority = Swi_numPriorities - 1; /* Max Priority Swi */ - suspendResumeSwi = Swi_create(IpcPower_suspendSwi, &swiParams, NULL); - IpcPower_sleepMode(IpcPower_SLEEP_MODE_DEEPSLEEP); /* Setup IDLEMODE and STANDBYMODE in DSP_SYS_SYSCONFIG */ @@ -268,11 +251,17 @@ Void IpcPower_init() /* Setup DSP_SYS_IRQWAKEEN0/1 */ IpcPower_getWugen(&wugenEvtMask); - /* TODO: Add DSP2 support */ - wugenEvtMask.mevt0 |= VAYU_DSP1_WUGEN_INT_MASK0; - wugenEvtMask.mevt1 |= VAYU_DSP1_WUGEN_INT_MASK1; + if (DNUM == 0) { /* DSP1 */ + wugenEvtMask.mevt0 |= VAYU_DSP1_WUGEN_INT_MASK0; + wugenEvtMask.mevt1 |= VAYU_DSP1_WUGEN_INT_MASK1; + } + else { + wugenEvtMask.mevt0 |= VAYU_DSP2_WUGEN_INT_MASK0; + wugenEvtMask.mevt1 |= VAYU_DSP2_WUGEN_INT_MASK1; + } IpcPower_setWugen(&wugenEvtMask); } +#undef FXNN /* * ======== IpcPower_exit ======== @@ -311,30 +300,10 @@ Void IpcPower_suspend() */ Void IpcPower_idle() { + Hwi_disable(); IpcPower_idleCount++; - if (IpcPower_deepSleep) { - /* Set deepsleep mode */ - REG32(PDCCMD_REG) = SLEEP_MODE; - REG32(PDCCMD_REG); - } - - asm(" mfence"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" idle"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); - asm(" nop"); + IpcPower_callIdle(); } /* @@ -505,11 +474,12 @@ Void IpcPower_preSuspend(Void) Void IpcPower_postResume(Void) { /* Restore timer registers */ - Timer_restoreRegisters(tickTimerHandle, NULL); - Timer_start(tickTimerHandle); + if (tickTimerHandle != NULL) { + Timer_restoreRegisters(tickTimerHandle, NULL); + Timer_start(tickTimerHandle); + } /* Call all user registered resume callback functions */ IpcPower_callUserFxns(IpcPower_Event_RESUME); - IpcPower_resumeCount++; } diff --git a/packages/ti/pm/IpcPowerDsp_idle_dra7xx.s66 b/packages/ti/pm/IpcPowerDsp_idle_dra7xx.s66 new file mode 100644 index 0000000..2663216 --- /dev/null +++ b/packages/ti/pm/IpcPowerDsp_idle_dra7xx.s66 @@ -0,0 +1,82 @@ +; +; Copyright (c) 2015, Texas Instruments Incorporated +; All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; * Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; * Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; * Neither the name of Texas Instruments Incorporated nor the names of +; its contributors may be used to endorse or promote products derived +; from this software without specific prior written permission. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +; EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +; +; +; ======== IpcPowerDsp_idle_dra7xx.s66 ======== +; +; + .if $isdefed("__TI_ELFABI__") + .if __TI_ELFABI__ + .asg IpcPower_callIdle, _IpcPower_callIdle + .endif + .endif + + .global _IpcPower_callIdle + + .align 4 + +; +; ======== IpcPower_callIdle ======== +; +; IpcPower_callIdle() +; + + .sect ".text:IpcPower_callIdle" + .clink + +_IpcPower_callIdle: + .asmfunc + .nocmp + + ; must enter this function with interrupts disabled + ; workaround: invalidate prefetch buffer in the xmc + mfence + mvk 0x0300,b5 + mvkh 0x8000000,b5 + || mvk 1,b4 + stw b4,*b5[0] + add 4,b5,a3 + ldw *+a3[0],a3 + nop ; pad rest of fetch packet + + ; idle the CPU with a simultaneous interrupt enable (GIE=1) + mvc csr, b4 + or 1, b4, b4 ; set GIE + mvc b4, csr + || idle + nop ; pad rest of fetch packet + nop + + ; return back to IpcPower_idle API + b b3 + nop 5 + + .endasmfunc diff --git a/packages/ti/pm/IpcPower_null.c b/packages/ti/pm/IpcPower_null.c new file mode 100644 index 0000000..aebb056 --- /dev/null +++ b/packages/ti/pm/IpcPower_null.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015, Texas Instruments Incorporated + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/** ============================================================================ + * @file IpcPowerDsp_null.c + * + * @brief Stubs for IpcPower API when power management is not wanted. + * + * ============================================================================ + */ + +#include + +#include + +/* + * ======== IpcPower_getWugenEvtMask ======== + */ +Void IpcPower_getWugenEvtMask(IpcPower_WugenEvtMask *mask) +{ +} + +/* + * ======== IpcPower_setWugenEvtMask ======== + */ +Void IpcPower_setWugenEvtMask(IpcPower_WugenEvtMask *mask) +{ +} + +/* + * ======== IpcPower_init ======== + */ +Void IpcPower_init() +{ +} + +/* + * ======== IpcPower_exit ======== + */ +Void IpcPower_exit() +{ +} + +/* + * ======== IpcPower_suspend ======== + */ +Void IpcPower_suspend() +{ +} + +/* + * ======== IpcPower_idle ======== + */ +Void IpcPower_idle() +{ +} + +/* + * ======== IpcPower_wakeLock ======== + */ +Void IpcPower_wakeLock() +{ +} + +/* + * ======== IpcPower_wakeUnlock ======== + */ +Void IpcPower_wakeUnlock() +{ +} + +/* + * ======== IpcPower_hibernateLock ======== + */ +UInt IpcPower_hibernateLock() +{ + return (0); +} + +/* + * ======== IpcPower_hibernateUnlock ======== + */ +UInt IpcPower_hibernateUnlock() +{ + return (0); +} + + +/* + * ======== IpcPower_canHibernate ======== + */ +Bool IpcPower_canHibernate() +{ + return (FALSE); +} + +/* + * ======== IpcPower_registerCallback ======== + */ +Int IpcPower_registerCallback(Int event, IpcPower_CallbackFuncPtr cbck, + Ptr data) +{ + return (IpcPower_E_FAIL); +} + +/* + * ======== IpcPower_unregisterCallback ======== + */ +Int IpcPower_unregisterCallback(Int event, IpcPower_CallbackFuncPtr cbck) +{ + return (IpcPower_E_FAIL); +} + +/* + * ======== IpcPower_preSuspend ======== + */ +Void IpcPower_preSuspend(Void) +{ +} + +/* + * ======== IpcPower_postResume ======== + */ +Void IpcPower_postResume(Void) +{ +} diff --git a/packages/ti/pm/package.bld b/packages/ti/pm/package.bld index f2b7a32..dec9d2f 100644 --- a/packages/ti/pm/package.bld +++ b/packages/ti/pm/package.bld @@ -94,6 +94,7 @@ libArray.push( name: "ti.pm_dra7xx_dsp", sources: [ "IpcPowerDsp_dra7xx", + "IpcPowerDsp_idle_dra7xx", ], isas: [ "66" ], devices: [ @@ -105,6 +106,16 @@ libArray.push( } ); +/* library for when PM is not needed */ +libArray.push( + { + name: "ti.pm_null", + sources: [ + "IpcPower_null", + ], + isas: [ "66", "v7M", "v7M4", "64T" ], + } +); /* ==== loop over array of libraries ==== */ for (var i = 0; i < libArray.length; i++) { diff --git a/packages/ti/pm/package.xs b/packages/ti/pm/package.xs index 3a07512..2d998d7 100644 --- a/packages/ti/pm/package.xs +++ b/packages/ti/pm/package.xs @@ -35,6 +35,8 @@ * */ +var powerEnabled = false; + /* * ======== init ======== */ @@ -44,22 +46,6 @@ function init() return; } - if (Program.build.target.name.match(/C64T/)) { - var Power = xdc.useModule('ti.sysbios.family.c64p.tesla.Power'); - } - - /* plug-in the power event hooks for SMP/BIOS */ - if (Program.build.target.isa.match(/v7M4/) && - (Program.platformName.match(/IPU/) || - Program.platformName.match(/ipu/))) { - var BIOS = xdc.module('ti.sysbios.BIOS'); - if (BIOS.smpEnabled) { - var Power = xdc.useModule('ti.sysbios.family.arm.ducati.smp.Power'); - Power.preSuspendHooks.$add("&IpcPower_preSuspend"); - Power.postSuspendHooks.$add("&IpcPower_postResume"); - } - } - if (Program.build.target.name.match(/M3/) && !Program.platformName.match(/ipu/)) { Program.sectMap[".ipcpower_data"] = new Program.SectionSpec(); @@ -80,6 +66,31 @@ function close() Program.exportModule('ti.sysbios.knl.Idle'); xdc.useModule('ti.sysbios.timers.dmtimer.Timer'); + + /* Find out if PM is wanted */ + if ((("ti.sysbios.family.c66.vayu.Power" in xdc.om) && + (xdc.module('ti.sysbios.family.c66.vayu.Power').$used)) || + (("ti.sysbios.family.c64p.tesla.Power" in xdc.om) && + (xdc.module('ti.sysbios.family.c64p.tesla.Power').$used)) || + (("ti.sysbios.family.arm.ducati.smp.Power" in xdc.om) && + (xdc.module('ti.sysbios.family.arm.ducati.smp.Power').$used))) { + powerEnabled = true; + } + + /* plug-in the power event hooks for SMP/BIOS */ + if (Program.build.target.isa.match(/v7M4/) && + (Program.platformName.match(/IPU/) || + Program.platformName.match(/ipu/))) { + var BIOS = xdc.module('ti.sysbios.BIOS'); + if ((BIOS.smpEnabled) && + ("ti.sysbios.family.arm.ducati.smp.Power" in xdc.om)) { + var Power = xdc.module('ti.sysbios.family.arm.ducati.smp.Power'); + if (Power.$used) { + Power.preSuspendHooks.$add("&IpcPower_preSuspend"); + Power.postSuspendHooks.$add("&IpcPower_postResume"); + } + } + } } /* @@ -119,22 +130,28 @@ function getLibs(prog) return ""; /* nothing to contribute */ } - /* make sure the library exists, else fallback to a built library */ - file = "lib/" + profile + "/ti.pm" + smp + platform + ".a" + suffix; - if (java.io.File(this.packageBase + file).exists()) { - libAry.push(file); + /* Use the 'null' implementation if PM is not needed */ + if (powerEnabled == false) { + libAry.push("lib/" + profile + "/ti.pm_null.a" + suffix); } else { - file = "lib/release/ti.pm" + smp + platform + ".a" + suffix; + /* make sure the library exists, else fallback to a built library */ + file = "lib/" + profile + "/ti.pm" + smp + platform + ".a" + suffix; if (java.io.File(this.packageBase + file).exists()) { libAry.push(file); } else { - /* fallback to a compatible library built by this package */ - for (var p in this.build.libDesc) { - if (suffix == this.build.libDesc[p].suffix) { - libAry.push(p); - break; + file = "lib/release/ti.pm" + smp + platform + ".a" + suffix; + if (java.io.File(this.packageBase + file).exists()) { + libAry.push(file); + } + else { + /* fallback to a compatible library built by this package */ + for (var p in this.build.libDesc) { + if (suffix == this.build.libDesc[p].suffix) { + libAry.push(p); + break; + } } } }