示例#1
0
/*
 *  ======== Power_signalEvent ========
 *  Signal a Power event to registered clients.
 *
 */
Power_Status Power_signalEvent(Power_Event eventType, UArg eventArg1,
    UArg eventArg2, UInt notifyTimeout)
{
    Power_Status status;
    UInt key;

    /* check for out of range event type */
    if ((eventType < 0) || (eventType >= Power_INVALIDEVENT)) {
        return (Power_EINVALIDEVENT);
    }

    /* disable task scheduling */
    key = Task_disable();

    /* notify clients registered for this event */
    status = Power_notify(eventType, notifyTimeout, Power_SigType_EXTERNAL, 
        eventArg1, eventArg2);

    /* reenable task scheduling */
    Task_restore(key);

    /* map a non-timeout error to Power_EFAIL */
    if ((status != Power_ETIMEOUT) && (status != Power_SOK)) {
        status = Power_EFAIL;
    }

    return (status);
}
示例#2
0
/*
 *  ======== Power_changeSetpoint ========
 *  Initiate a change to the F/V setpoint of the CPU, or the peripheral domain.
 *
 */
Power_Status Power_changeSetpoint(Power_Domain domain, UInt newSetpoint,
    UInt notifyTimeout)
{
    PSCL_Status statusPSCL = PSCL_CANNOT_CHANGE_SETPOINT;
    Power_Status status = Power_SOK;
    Power_Status statusNotifyCPU = Power_SOK;
    Power_Status statusNotifyPER = Power_SOK;
    Bool notifyCPU = FALSE;
    Bool notifyPER = FALSE;
    UInt willChange = FALSE;
    Bool proceed = FALSE;
    Types_FreqHz cpuFreq;
    UInt previousSPPER;
    UInt previousSP;
    UInt disallowed;
    PSCL_ClkID clk;
    UInt frequency;
    UInt voltage;
    UInt maskSP;
    UInt taskKey;
    UInt swiKey;
    UInt key;

    /* make sure V/F scaling is supported */
    if (!ti_sysbios_family_c674_Power_enableScaling) {
        status = Power_ENOTIMPLEMENTED;
    }

    /* check to make sure V/F scaling initialized OK */
    else if (Power_module->PSCLinitOK == FALSE) {
        status = Power_EINITFAILURE;
    }

    /* check that domain ID is valid */
    else if ((domain != Power_CPU) && (domain != Power_PER)) {
        status = Power_EINVALIDVALUE;
    }

    /* check if setpoint ID is out of range for the specified domain ID */
    else if (((domain == Power_CPU) && (newSetpoint > 
                 (Power_module->numSPCPU - 1))) ||
             ((domain == Power_PER) && (newSetpoint > 
                 (Power_module->numSPPER - 1)))) {
        status = Power_EOUTOFRANGE;
    }

    else {

        /* convert requested setpoint into a mask bit */
        maskSP = 1 << newSetpoint;

        /* go atomic */
        key = Hwi_disable();

        /* now check the requested SP against disallowed SP constraints */
        if (domain == Power_CPU) {
            disallowed = maskSP & Power_module->disallowedSetpointsCPU;
        }
        else {
            disallowed = maskSP & Power_module->disallowedSetpointsPER;
        }

        /* if the SP is *not* disallowed, check and set the 'busy' flag */
        if (disallowed == 0) {

            if (Power_module->busy == FALSE) {
                Power_module->busy = TRUE;
                proceed = TRUE;
            }
            else {
                status = Power_EBUSY;
            }
        }
        else {
            status = Power_ENOTSUPPORTED;
        }

        /* end ATOMIC */
        Hwi_restore(key);

        if (proceed == TRUE) {

            /* determine PSCL clock ID */
            clk = (PSCL_ClkID) domain == Power_CPU ? PSCL_CPU_CLK : 
                PSCL_PER_CLK;

            /* disable Task scheduling; allow Swi & Hwi for completion */
            taskKey = Task_disable();

            /* set flag for domain to be notified for SP change */
            if (domain == Power_CPU) {
                notifyCPU = TRUE;
            }
            else {
                notifyPER = TRUE;
            }

            /* if voltage scaling enabled, call to PSCL to see if this setpoint
               change will result in a voltage change; if yes, then must notify
               for other clk domain too, as there will be a voltage scale even
               though that clk frequency isn't changing */
            if (Power_module->currentConfig.scaleVoltage == TRUE) {

                PSCL_queryWillChangeVoltage(clk, newSetpoint, &willChange);

                if (willChange == TRUE) {
                    if (domain == Power_CPU) {
                        notifyPER = TRUE;
                    }
                    else {
                        notifyCPU = TRUE;
                    }
                }
            }

            /* now send any pre-notifications for CPU domain */
            if (notifyCPU == TRUE) {

                /* set nextSP to indicate the pending setpoint */
                if (domain == Power_CPU) {
                    Power_module->nextSP = newSetpoint; /* yes, new setpoint */
                    previousSP = Power_module->currentSetpointCPU;
                }
                else {                               /* not new CPU setpoint */
                    Power_module->nextSP = Power_module->currentSetpointCPU; 
                    previousSP = Power_module->currentSetpointCPU;
                }

                /* notify clients registered for pre CPU SP notification */
                statusNotifyCPU = 
                    Power_notify(Power_PENDING_CPU_SETPOINTCHANGE, 
                    notifyTimeout, Power_SigType_INTERNAL, NULL, NULL);
             }

            /* now send any pre-notifications for PER domain */
            if ((statusNotifyCPU == Power_SOK) && (notifyPER == TRUE)) {

                /* set nextSPPER to indicate the pending setpoint */
                if (domain == Power_CPU) {           /* not new PER SP */
                    Power_module->nextSPPER = Power_module->currentSetpointPER;
                    previousSPPER = Power_module->currentSetpointPER;
                }
                else {
                    Power_module->nextSPPER = newSetpoint; /* yes, new PER SP */
                    previousSPPER = Power_module->currentSetpointPER;
                }

                /* notify clients registered for pre PER SP notification */
                statusNotifyPER = 
                    Power_notify(Power_PENDING_PER_SETPOINTCHANGE,
                    notifyTimeout, Power_SigType_INTERNAL, NULL, NULL);
            }


            /* if all 'pre' notifications succeeded... do the scaling op */
            if ((statusNotifyCPU == Power_SOK) &&
                (statusNotifyPER == Power_SOK)) {

                swiKey = Swi_disable();

                /* call to PSCL to change the setpoint */
                statusPSCL = PSCL_changeSetpoint(clk, newSetpoint,
                    Power_module->currentConfig.scaleVoltage,
                    Power_module->currentConfig.waitForVoltageScale,NULL,NULL);

                Swi_restore(swiKey);
            }

            /* if scaling operation successful... */
            if (statusPSCL == PSCL_OK) {

                /* update previous and current SP globals */
                if (notifyCPU == TRUE) {
                    Power_module->currentSetpointCPU = Power_module->nextSP;
                    Power_module->previousSP = previousSP;
                }
                if (notifyPER == TRUE) {
                    Power_module->currentSetpointPER = Power_module->nextSPPER;
                    Power_module->previousSPPER = previousSPPER;
                }

                /* if scaled the CPU frequency... tell BIOS about it */
                if (domain == Power_CPU) {
                    Power_getSetpointInfo(Power_CPU, newSetpoint, &frequency,
                        &voltage);
                    cpuFreq.lo = frequency * 1000; /* convert kHz to Hz */
                    cpuFreq.hi = 0;             
                    BIOS_setCpuFreq(&cpuFreq);
                }

                /* now notify post-notification clients */
                if (notifyCPU == TRUE) {

                    /* notify clients registered of post CPU SP change */
                    statusNotifyCPU = 
                        Power_notify(Power_DONE_CPU_SETPOINTCHANGE, 
                            notifyTimeout, Power_SigType_INTERNAL, NULL, NULL);
                }

                if ((statusNotifyCPU == Power_SOK) && (notifyPER == TRUE)) {

                    /* notify clients registered of post PER SP change */
                    statusNotifyPER = 
                        Power_notify(Power_DONE_PER_SETPOINTCHANGE,
                            notifyTimeout, Power_SigType_INTERNAL, NULL, NULL);
                }
            }

            /* done, so clear Power busy flag */
            Power_module->busy = FALSE;

            /* resume Tasking */
            Task_restore(taskKey);

            /* figure out return code */
            if (statusPSCL == PSCL_INVALID_SETPOINT) {
                status = Power_EOUTOFRANGE;  /* invalid SP according to PSCL */
            }
            else if ((statusNotifyCPU == Power_ETIMEOUT) ||
                     (statusNotifyPER == Power_ETIMEOUT) ) {
                status = Power_ETIMEOUT;     /* notification timeout */
            }
            else if ((status != Power_SOK) || (statusPSCL != PSCL_OK)) {
                status = Power_EFAIL;        /* convert to 'general failure' */
            }
        }
    }

    return (status);
}
/*
 *  ======== Power_sleep ========
 */
Power_Status Power_sleep(Power_SleepState sleepState, UArg arg0, UArg arg1)
{
    Power_Status status = Power_SOK;
    UInt xosc_hf_active = FALSE;
    Power_Event postEventLate;
    UInt32 poweredDomains = 0;
    Bool exitNow = FALSE;
    Power_Event preEvent;
    Power_Event postEvent;
    UInt32 constraints;
    Bool retainCache = FALSE;
    UInt32 modeVIMS;
    UInt taskKey;
    UInt swiKey;
    UInt hwiKey;

    /* first validate the sleep code */
    if ( sleepState != Power_STANDBY) {
        status = Power_EFAIL;
    }

    if (status == Power_SOK) {

        /* make sure Power is not still busy with a previous transition */
        hwiKey = Hwi_disable();

        if (Power_module->state == Power_ACTIVE) {

            /* set transition state to entering sleep */
            Power_module->state = Power_ENTERING_SLEEP;
        }
        else {
            exitNow = TRUE;
        }

        Hwi_restore(hwiKey);

        if (exitNow == TRUE) {
            status = Power_EBUSY;
        }

        else {

            /* setup sleep vars */
            if (sleepState == Power_STANDBY) {
                preEvent = Power_ENTERING_STANDBY;
                postEvent = Power_AWAKE_STANDBY;
                postEventLate = Power_AWAKE_STANDBY_LATE;
            }

            /* disable Task scheduling; allow Swis and Hwis for notifications */
            taskKey = Task_disable();

            /* signal all clients registered for pre-sleep notification */
            status = Power_notify(preEvent);

            /* check for any error */
            if (status != Power_SOK) {
                Power_module->state = Power_ACTIVE;
                Task_restore(taskKey);          /* re-enable scheduler */
                return (status);
            }

            /* now disable Swi scheduling */
            swiKey = Swi_disable();

            /* freeze the IOs on the boundary between MCU and AON */
            AONIOCFreezeEnable();

            /* if XOSC_HF is active, force it off */
            if(OSCClockSourceGet(OSC_SRC_CLK_HF) == OSC_XOSC_HF) {
                xosc_hf_active = TRUE;
                ti_sysbios_family_arm_cc26xx_Power_XOSC_HF(DISABLE);
            }

            /* allow AUX to power down */
            AONWUCAuxWakeupEvent(AONWUC_AUX_ALLOW_SLEEP);

            /* make sure writes take effect */
            SysCtrlAonSync();

            /* invoke specific sequences to activate sleep states... */

            if (sleepState == Power_STANDBY) {

                /* query and save domain states before powering them off */
                if (Power_getDependencyCount(DOMAIN_RFCORE)) {
                    poweredDomains |= PRCM_DOMAIN_RFCORE;
                }
                if (Power_getDependencyCount(DOMAIN_SERIAL)){
                    poweredDomains |= PRCM_DOMAIN_SERIAL;
                }
                if (Power_getDependencyCount(DOMAIN_PERIPH)) {
                    poweredDomains |= PRCM_DOMAIN_PERIPH;
                }

                /* gate running deep sleep clocks for Crypto and DMA */
                if (Power_getDependencyCount(PERIPH_CRYPTO)) {
                    PRCMPeripheralDeepSleepDisable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_CRYPTO].driverlibID);
                }
                if (Power_getDependencyCount(PERIPH_UDMA)) {
                    PRCMPeripheralDeepSleepDisable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_UDMA].driverlibID);
                }
                /* make sure clock settings take effect */
                PRCMLoadSet();

                /* request power off of domains in the MCU voltage domain */
                PRCMPowerDomainOff(poweredDomains | PRCM_DOMAIN_CPU);

                /* request uLDO during standby */
                PRCMMcuUldoConfigure(true);

                /* query constraints to determine if cache should be retained */
                constraints = Power_getConstraintInfo();
                if ((constraints & Power_SB_VIMS_CACHE_RETAIN) != 0) {
                    retainCache = TRUE;
                }

                /* if don't want retention in standby, disable it now ... */
                if (retainCache == FALSE) {
                    modeVIMS = VIMSModeGet(VIMS_BASE);
                    /* wait if invalidate in progress... */
                    while (modeVIMS == VIMS_MODE_CHANGING) {
                        modeVIMS = VIMSModeGet(VIMS_BASE);
                    }
                    PRCMCacheRetentionDisable();
                    VIMSModeSet(VIMS_BASE, VIMS_MODE_OFF);
                }

                /* setup recharge parameters */
                SysCtrlSetRechargeBeforePowerDown(XoscInHighPowerMode);

                /* make sure all writes have taken effect */
                SysCtrlAonSync();

                /* invoke deep sleep to go to STANDBY */
                PRCMDeepSleep();

                /* if didn't retain cache in standby, re-enable retention now */
                if (retainCache == FALSE) {
                    VIMSModeSet(VIMS_BASE, modeVIMS);
                    PRCMCacheRetentionEnable();
                }

                /* force power on of AUX to keep it on when system is not
                 * sleeping; this also counts as a write to the AON interface
                 * ensuring that a following sync of the AON interface will
                 * force an update of all registers
                 */
                AONWUCAuxWakeupEvent(AONWUC_AUX_WAKEUP);
                while(!(AONWUCPowerStatusGet() & AONWUC_AUX_POWER_ON)) {};

                /* if XOSC_HF was forced off above, initiate switch back */
                if (xosc_hf_active == TRUE) {
                    ti_sysbios_family_arm_cc26xx_Power_XOSC_HF(ENABLE);
                }

                /* restore power domain states in effect before standby */
                PRCMPowerDomainOn(poweredDomains);
                while (PRCMPowerDomainStatus(poweredDomains) !=
                    PRCM_DOMAIN_POWER_ON){};

                /* restore deep sleep clocks of Crypto and DMA */
                if (Power_getDependencyCount(PERIPH_CRYPTO)) {
                    PRCMPeripheralDeepSleepEnable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_CRYPTO].driverlibID);
                }
                if (Power_getDependencyCount(PERIPH_UDMA)) {
                    PRCMPeripheralDeepSleepEnable(
                        ti_sysbios_family_arm_cc26xx_Power_db[
                            PERIPH_UDMA].driverlibID);
                }
                /* make sure clock settings take effect */
                PRCMLoadSet();
            }

            /* release request for uLDO */
            PRCMMcuUldoConfigure(false);

            /* set transition state to EXITING_SLEEP */
            Power_module->state = Power_EXITING_SLEEP;

            /*
             * signal clients registered for early post-sleep notification;
             * this should be used to initialize any timing critical or IO
             * dependent hardware
             */
            status = Power_notify(postEvent);

            /* disable IO freeze and ensure RTC shadow value is updated */
            AONIOCFreezeDisable();
            SysCtrlAonSync();

            /* re-enable interrupts */
            CPUcpsie();

            /* signal all clients registered for late post-sleep notification */
            status = Power_notify(postEventLate);

            /* now clear the transition state before re-enabling scheduler */
            Power_module->state = Power_ACTIVE;

            /* re-enable Swi scheduling */
            Swi_restore(swiKey);

            /* adjust recharge parameters */
            SysCtrlAdjustRechargeAfterPowerDown();

            /* re-enable Task scheduling */
            Task_restore(taskKey);

            /* check for any notification error */
            if (status != Power_SOK) {
                return (status);
            }
        }
    }

    return (status);
}
示例#4
0
/*
 *  ======== Power_sleepDSP ========
 */
Power_Status Power_sleepDSP(UInt sleepCode, UInt sleepArg, UInt notifyTimeout)
{
    Power_Status status = Power_SOK;
    Bool exitNow = FALSE;
    Power_Event preEvent;
    Power_Event postEvent;
    PMI_Sleep sleepMode;
    UInt taskKey;
    UInt swiKey;
    UInt hwiKey;

    /* first validate the sleep code */
    if ( (sleepCode != Power_STANDBY) &&
         (sleepCode != Power_SLEEP) &&
         (sleepCode != Power_DEEPSLEEP) ) {
        status = Power_ENOTIMPLEMENTED;
    }

    /* make sure sleep request doesn't violate a registered constraint */
    else if ( ( (sleepCode == Power_STANDBY) &&
                ((Power_module->disallowedSleepModes & Power_STANDBY) != 0) ) ||
              ( (sleepCode == Power_SLEEP) &&
                ((Power_module->disallowedSleepModes & Power_SLEEP) != 0) ) ||
              ( (sleepCode == Power_DEEPSLEEP) &&
               ((Power_module->disallowedSleepModes & Power_DEEPSLEEP) != 0))) {
        status = Power_ENOTSUPPORTED;
    }

    /* check for valid sleepArg */
    else if (sleepCode == Power_DEEPSLEEP) {
        if ((sleepArg != Power_EXTERNAL) && (sleepArg != Power_RTC_ALARM)) {
            status = Power_EINVALIDVALUE;
        }
    }

    if (status == Power_SOK) {

        /* make sure Power is not still busy with a previous transition */
        hwiKey = Hwi_disable();

        if (Power_module->busy == FALSE) {
            Power_module->busy = TRUE;
        }
        else {
            exitNow = TRUE;
        }

        Hwi_restore(hwiKey);

        if (exitNow == TRUE) {
            status = Power_EBUSY;
        }

        else {

            /* setup sleep vars */
            if (sleepCode == Power_STANDBY) {
                preEvent = Power_GOINGTOSTANDBY;
                postEvent = Power_AWAKEFROMSTANDBY;
                sleepMode = PMI_STANDBY;
            }
            else if (sleepCode == Power_SLEEP) {
                preEvent = Power_GOINGTOSLEEP;
                postEvent = Power_AWAKEFROMSLEEP;
                sleepMode = PMI_SLEEP;
            }
            else {
                preEvent = Power_GOINGTODEEPSLEEP;
                postEvent = Power_AWAKEFROMDEEPSLEEP;
                sleepMode = PMI_DEEPSLEEP;
            }

            /* disable Task scheduling; allow Swis and Hwis for notifications */
            taskKey = Task_disable();

            /* signal all clients registered for pre-sleep notification */
            status = Power_notify(preEvent, notifyTimeout, 
                Power_SigType_INTERNAL, NULL, NULL);

            /* check for timeout or any other error */
            if (status != Power_SOK) {
                Power_module->busy = FALSE;     /* clear busy */
                Task_restore(taskKey);          /* re-enable scheduler */
                return (status);
            }

            /* now disable Swi scheduling */
            swiKey = Swi_disable();

            /* start the sleep sequence */
            hwiKey = Hwi_disable();

            /* call to PMI to go to and wake from sleep... */
            PMI_sleepCPU(sleepMode, Power_module->currentConfig.scaleVoltage,
                (UInt) sleepArg);

            /* when get here CPU has already processed the wakeup interrupt */

            /* restore the previous interrupt enable state */
            Hwi_restore(hwiKey);

            /* re-enable Swi scheduling */
            Swi_restore(swiKey);

            /* signal all clients registered for post-sleep notification */
            status = Power_notify(postEvent, notifyTimeout, 
                Power_SigType_INTERNAL, NULL, NULL);

            /* now clear the busy flag before re-enabling scheduler */
            Power_module->busy = FALSE;

            /* re-enable Task scheduling */
            Task_restore(taskKey);

            /* check for timeout or other notification error */
            if (status != Power_SOK) {
                return (status);
            }
        }
    }

    return (status);
}
/*
 *  ======== Power_shutdown ========
 */
Power_Status Power_shutdown(UArg arg)
{
    Power_Status status = Power_EFAIL;
    Bool exitNow = FALSE;
    UInt32 constraints;
    UInt hwiKey;

    /* make sure shutdown request doesn't violate a constraint */
    constraints = Power_getConstraintInfo();
    if ((constraints & (Power_SD_DISALLOW)) != 0) {
        status = Power_ECHANGE_NOT_ALLOWED;
    }

    if (status == Power_EFAIL) {

        /* make sure Power is not still busy with a previous transition */
        hwiKey = Hwi_disable();

        if (Power_module->state == Power_ACTIVE) {
            /* set new transition state to entering shutdown */
            Power_module->state = Power_SHUTDOWN;
        }
        else {
            exitNow = TRUE;
        }

        Hwi_restore(hwiKey);

        if (exitNow == TRUE) {
            status = Power_EBUSY;
        }

        else {

            /* disable interrupts as start the shutdown sequence */
            Hwi_disable();

            /* signal all clients registered for pre-shutdown notification */
            status = Power_notify(Power_ENTERING_SHUTDOWN);

            /* check for any error */
            if (status != Power_SOK) {
                Power_module->state = Power_ACTIVE;
                CPUcpsie();
                return (status);
            }

            /* proceed with shutdown sequence ... */

            /* switch to RCOSC_HF and RCOSC_LF */
            OSCInterfaceEnable();
            if(OSCClockSourceGet(OSC_SRC_CLK_HF) != OSC_RCOSC_HF) {
                OSCClockSourceSet(OSC_SRC_CLK_HF | OSC_SRC_CLK_MF,
                    OSC_RCOSC_HF);
                while(!OSCHfSourceReady());
                OSCHfSourceSwitch();
            }
            OSCClockSourceSet(OSC_SRC_CLK_LF,OSC_RCOSC_LF);
            while(OSCClockSourceGet(OSC_SRC_CLK_LF) != OSC_RCOSC_LF);
            OSCInterfaceDisable();

            /* make sure DMA and CRYTO clocks are off in deep-sleep */
            PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_CRYPTO);
            PRCMPeripheralDeepSleepDisable(PRCM_PERIPH_UDMA);
            PRCMLoadSet();
            while(!PRCMLoadGet()){};

            /* power OFF AUX and disconnect from bus */
            AUXWUCPowerCtrl(AUX_WUC_POWER_OFF);

            /* remove AUX force ON */
            HWREG(AON_WUC_BASE + AON_WUC_O_AUXCTL) &=
                ~AON_WUC_AUXCTL_AUX_FORCE_ON;

            /*
             * reset AON event source IDs to avoid pending events powering
             * on MCU/AUX
             */
            HWREG(AON_EVENT_BASE + AON_EVENT_O_MCUWUSEL) = 0x3F3F3F3F;
            HWREG(AON_EVENT_BASE + AON_EVENT_O_AUXWUSEL) = 0x003F3F3F;

            /* sync AON */
            HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);

            /*
             * enable shutdown - this latches the IOs, so configuration of
             * IOCFGx registers must be done prior to this
             */
            AONWUCShutDownEnable();

            /* sync AON */
            HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);

            /* wait until AUX powered off */
            while (AONWUCPowerStatusGet() & AONWUC_AUX_POWER_ON);

            /* request to power off MCU when go to deep sleep */
            PRCMMcuPowerOff();

            /* turn off power domains inside MCU VD (BUS, FL_BUS, RFC, CPU) */
            PRCMPowerDomainOff(PRCM_DOMAIN_RFCORE | PRCM_DOMAIN_SERIAL |
                PRCM_DOMAIN_PERIPH | PRCM_DOMAIN_CPU | PRCM_DOMAIN_VIMS);

            /* deep sleep to activate shutdown */
            PRCMDeepSleep();
        }
    }

    Power_module->state = Power_ACTIVE;

    /* if get here failed to shutdown, return failure code */
    return (Power_EFAIL);
}