/*
 *  ======== PowerMSP432_updateFreqs ========
 */
void PowerMSP432_updateFreqs(PowerMSP432_Freqs *freqs)
{
    Types_FreqHz cpuFreq;

    cpuFreq.hi = 0;
    cpuFreq.lo = freqs->MCLK;
    BIOS_setCpuFreq(&cpuFreq);

    ClockFreqs_setFrequency(ClockFreqs_Clock_ACLK, freqs->ACLK);
    ClockFreqs_setFrequency(ClockFreqs_Clock_SMCLK, freqs->SMCLK);
    ClockFreqs_setFrequency(ClockFreqs_Clock_HSMCLK, freqs->HSMCLK);
}
Esempio n. 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);
}