Beispiel #1
0
/**
 * PmPwrDnHandler() - Power down island/domain
 * @nodePtr Pointer to node-structure of power island/dom to be powered off
 *
 * @return  Operation status of power down procedure (done by pmu-rom)
 */
static int PmPwrDnHandler(PmNode* const nodePtr)
{
	int status = XST_PM_INTERNAL;

	if (NULL == nodePtr) {
		goto done;
	}

	/* Call proper PMU-ROM handler as needed */
	switch (nodePtr->nodeId) {
	case NODE_FPD:
		status = PmPowerDownFpd();
		break;
	case NODE_APU:
		status = XST_SUCCESS;
		break;
	case NODE_RPU:
		status = XpbrPwrDnRpuHandler();
		break;
	default:
		PmDbg("unsupported node %s(%d)\n",
		      PmStrNode(nodePtr->nodeId), nodePtr->nodeId);
		break;
	}

	if (XST_SUCCESS == status) {
		nodePtr->currState = PM_PWR_STATE_OFF;
	}

done:
	PmDbg("%s\n", PmStrNode(nodePtr->nodeId));
	return status;
}
Beispiel #2
0
/**
 * PmGppFsmHandler() - FSM handler of a GPP slave
 * @slave       Slave whose state should be changed
 * @nextState   State the slave should enter
 *
 * @return      Status of performing transition action
 */
static int PmGppFsmHandler(PmSlave* const slave, const PmStateId nextState)
{
    int status = XST_PM_INTERNAL;
    PmSlaveGpp* gpp = (PmSlaveGpp*)slave->node.derived;

    switch (slave->node.currState) {
    case PM_GPP_SLAVE_STATE_ON:
        if (PM_GPP_SLAVE_STATE_OFF == nextState) {
            /* ON -> OFF*/
            status = gpp->PwrDn();
        } else {
            status = XST_NO_FEATURE;
        }
        break;
    case PM_GPP_SLAVE_STATE_OFF:
        if (PM_GPP_SLAVE_STATE_ON == nextState) {
            /* OFF -> ON */
            status = gpp->PwrUp();
        } else {
            status = XST_NO_FEATURE;
        }
        break;
    default:
        PmDbg("ERROR: Unknown state #%d\n", slave->node.currState);
        break;
    }
    if (XST_SUCCESS == status) {
        PmNodeUpdateCurrState(&slave->node, nextState);
    }

    return status;
}
Beispiel #3
0
/**
 * PmRequirementReleaseAll() - Called when master primary processor is forced to
 *                             power down, so all requirements of the processor
 *                             are automatically released.
 * @master  Master whose primary processor was forced to power down
 *
 * @return  Status of the operation of releasing all slaves used by the master
 *          and changing their state to the lowest possible.
 */
static int PmRequirementReleaseAll(const PmMaster* const master)
{
    int status;
    PmRequirementId i;

    for (i = 0; i < master->reqsCnt; i++) {
        if (0U != (PM_MASTER_USING_SLAVE_MASK & master->reqs[i].info)) {
            /* Clear flag - master is not using slave anymore */
            master->reqs[i].info &= ~PM_MASTER_USING_SLAVE_MASK;
            /* Release current and next requirements */
            master->reqs[i].currReq = 0U;
            master->reqs[i].nextReq = 0U;
            /* Update slave setting */
            status = PmUpdateSlave(master->reqs[i].slave);
            /* if pmu rom works correctly, status should be always ok */
            if (XST_SUCCESS != status) {
                PmDbg("ERROR setting slave node %s\n",
                      PmStrNode(master->reqs[i].slave->node.nodeId));
                break;
            }
        }
    }

    return status;
}
Beispiel #4
0
/**
 * PmMasterNotify() - Notify master channel of a state change in its primary processor
 * @master      Pointer to master object which needs to be notified
 * @event       Processor Event to notify the master about
 *
 * @return      Status of potential changing of slave states or success.
 *
 * Primary processor has changed its state, notify master to update its requirements
 * accordingly.
 */
int PmMasterNotify(PmMaster* const master, const PmProcEvent event)
{
    int status = XST_SUCCESS;

    switch (event) {
    case PM_PROC_EVENT_SLEEP:
        status = PmRequirementUpdateScheduled(master, true);
        break;
    case PM_PROC_EVENT_ABORT_SUSPEND:
        PmRequirementCancelScheduled(master);
        PmWakeUpCancelScheduled(master);
        break;
    case PM_PROC_EVENT_WAKE:
        if (PM_PROC_STATE_SLEEP == master->procs->node.currState) {
            PmWakeUpDisableAll(master);
        } else if (PM_PROC_STATE_FORCEDOFF ==
                   master->procs->node.currState) {
            PmRequirementRequestDefault(master);
        } else {
        }
        status = PmRequirementUpdateScheduled(master, false);
        break;
    case PM_PROC_EVENT_FORCE_PWRDN:
        status = PmRequirementReleaseAll(master);
        PmWakeUpCancelScheduled(master);
        break;
    default:
        status = XST_PM_INTERNAL;
        PmDbg("ERROR: undefined event #%d\n", event);
        break;
    }

    return status;
}
Beispiel #5
0
/**
 * PmWakeUpDisableAll() - Disable all wake-up sources of this master
 * @master  Pointer to a master whose wake-up sources are to be disabled
 */
static void PmWakeUpDisableAll(PmMaster* const master)
{
    u32 i;

    PmDbg("for %s\n", PmStrNode(master->procs->node.nodeId));
    for (i = 0; i < master->reqsCnt; i++) {
        if (0U != (master->reqs[i].info & PM_MASTER_WAKEUP_REQ_MASK)) {
            PmMasterId r;
            bool hasOtherReq = false;

            master->reqs[i].info &= ~PM_MASTER_WAKEUP_REQ_MASK;
            /*
             * Check if there are other masters waiting for slave's
             * wake-up.
             */
            for (r = 0U; r < master->reqs[i].slave->reqsCnt; r++) {
                if (0U != (master->reqs[i].slave->reqs[r]->info &
                           PM_MASTER_WAKEUP_REQ_MASK)) {
                    hasOtherReq = true;
                    break;
                }
            }
            if (false == hasOtherReq) {
                /*
                 * No other masters waiting for wake, disable
                 * wake event.
                 */
                PmSlaveWakeDisable(master->reqs[i].slave);
            }
        }
    }
}
Beispiel #6
0
/**
 * PmForcePowerDownChildren() - Forces power down for child nodes
 * @parent      pointer to power object whose children are to be turned off
 */
static void PmForcePowerDownChildren(const PmPower* const parent)
{
	u32 i;
	PmNode* child;
	PmProc* proc;

	for (i = 0U; i < parent->childCnt; i++) {
		child = parent->children[i];

		if ((false != PmChildIsInLowestPowerState(child)) ||
		    (true != HAS_SLEEP(child->ops))) {
			continue;
		}

		PmDbg("Powering OFF child node %s\n", PmStrNode(child->nodeId));

		/* Force the child's state to 0, which is its lowest power state */
		child->ops->sleep(child);
		child->currState = 0U;

		/* Special case: node is a processor, release slave-requirements */
		if (PM_TYPE_PROC == child->typeId) {
			proc = (PmProc*)child->derived;

			if ((NULL !=proc) && (true == proc->isPrimary)) {
				/* Notify master so it can release all requirements */
				PmMasterNotify(proc->master, PM_PROC_EVENT_FORCE_PWRDN);
			}
		}
	}

	return;
}
Beispiel #7
0
/**
 * PmTriggerPowerUp() - Triggered by child node (processor or slave) when it
 *                      needs its power islands/domains to be powered up
 * @power       Power node that needs to be powered up
 *
 * @return      Status of the power up operation.
 */
int PmTriggerPowerUp(PmPower* const power)
{
	int status = XST_SUCCESS;

	if (NULL == power) {
		goto done;
	}

	/*
	 * Multiple hierarchy levels of power islands/domains may need to be
	 * turned on (always top-down).
	 * Use iterative approach for MISRA-C compliance
	 */
	while ((true == IS_OFF(&power->node)) && (XST_SUCCESS == status)) {
		status = PmPowerUpTopParent(power);
	}

done:
#ifdef DEBUG_PM
	if (XST_SUCCESS != status) {
		PmDbg("ERROR #%d failed to power up\n", status);
	}
#endif

	return status;
}
Beispiel #8
0
/**
 * PmOpportunisticSuspend() - After a node goes to sleep, try to power off
 *                            parents
 * @powerParent Pointer to the power node which should try to suspend, as well
 *              its parents.
 */
void PmOpportunisticSuspend(PmPower* const powerParent)
{
	PmPower* power = powerParent;

	if (NULL == powerParent) {
		goto done;
	}

	do {
		PmDbg("Opportunistic suspend attempt for %s\n",
		      PmStrNode(power->node.nodeId));

		if ((false == PmHasAwakeChild(power)) &&
			(true == HAS_SLEEP(power->node.ops))) {
			/* Call sleep function of this power node */
			power->node.ops->sleep(&power->node);
			power = power->node.parent;
		} else {
			power = NULL;
		}
	} while (NULL != power);

done:
	return;
}
Beispiel #9
0
/**
 * PmPwrUpHandler() - Power up island/domain
 * @nodePtr Pointer to node-structure of power island/dom to be powered on
 *
 * @return  Operation status of power up procedure (done by pmu-rom)
 */
static int PmPwrUpHandler(PmNode* const nodePtr)
{
	int status = XST_PM_INTERNAL;

	PmDbg("%s\n", PmStrNode(nodePtr->nodeId));

	if (NULL == nodePtr) {
		goto done;
	}

	/* Call proper PMU-ROM handler as needed */
	switch (nodePtr->nodeId) {
	case NODE_FPD:
		status = XpbrPwrUpFpdHandler();
		if (XST_SUCCESS == status) {
			PmCrfRestoreContext();
		}
		break;
	case NODE_APU:
		status = XST_SUCCESS;
		break;
	case NODE_RPU:
	{
		u32 reg;

		status = XpbrPwrUpRpuHandler();

		/* release RPU island reset */
		reg = Xil_In32(CRL_APB_RST_LPD_TOP);
		reg &= ~CRL_APB_RST_LPD_TOP_RPU_PGE_RESET_MASK;
		Xil_Out32(CRL_APB_RST_LPD_TOP, reg);
		break;
	}
	default:
		PmDbg("ERROR - unsupported node %s(%d)\n",
		      PmStrNode(nodePtr->nodeId), nodePtr->nodeId);
		break;
	}
	if (XST_SUCCESS == status) {
		nodePtr->currState = PM_PWR_STATE_ON;
	}

done:
	return status;
}
Beispiel #10
0
/**
 * PmWakeUpCancelScheduled() - Cancel scheduled wake-up sources of the master
 * @master  Pointer to a master whose scheduled wake-up sources should be
 *          cancelled
 */
static void PmWakeUpCancelScheduled(PmMaster* const master)
{
    u32 i;

    PmDbg("%s\n", PmStrNode(master->procs->node.nodeId));

    for (i = 0; i < master->reqsCnt; i++) {
        master->reqs[i].info &= ~PM_MASTER_WAKEUP_REQ_MASK;
    }
}
Beispiel #11
0
/**
 * PmInitSuspendCb() - request a master to suspend itself
 * @master      Master to be asked to suspend
 * @reason      The reason of initiating the suspend
 * @latency     Not supported
 * @state       State to which the master should suspend
 * @timeout     How much time the master has to respond
 */
void PmInitSuspendCb(const PmMaster* const master, const u32 reason,
		     const u32 latency, const u32 state, const u32 timeout)
{
	PmDbg("of %s (%lu, %lu, %lu, %lu)\n", PmStrNode(master->nid), reason,
	      latency, state, timeout);

	IPI_REQUEST5(master->pmuBuffer, PM_INIT_SUSPEND_CB, reason, latency,
		     state, timeout);
	XPfw_Write32(IPI_PMU_0_TRIG, master->ipiMask);
}
Beispiel #12
0
/**
 * PmRequirementUpdateScheduled() - Triggers the setting for scheduled
 *                                  requirements
 * @master  Master which changed the state and whose scheduled requirements are
 *          triggered
 * @swap    Flag stating should current/default requirements be saved as next
 *
 * a) swap=false
 * Set scheduled requirements of a master without swapping current/default and
 * next requirements - means the current requirements will be dropped and
 * default requirements has no effect. Upon every self suspend, master has to
 * explicitly re-request slave requirements.
 * b) swap=true
 * Set scheduled requirements of a master with swapping current/default and
 * next requirements (swapping means the current/default requirements will be
 * saved as next, and will be configured once master wakes-up). If the master
 * has default requirements, default requirements are saved as next instead of
 * current requirements. Default requirements has priority over current
 * requirements.
 */
static int PmRequirementUpdateScheduled(const PmMaster* const master,
                                        const bool swap)
{
    int status;
    PmRequirementId i;

    PmDbg("%s\n", PmStrNode(master->procs[0].node.nodeId));

    for (i = 0; i < master->reqsCnt; i++) {
        if (master->reqs[i].currReq != master->reqs[i].nextReq) {
            u32 tmpReq = master->reqs[i].nextReq;

            if (true == swap) {
                if (0U != master->reqs[i].defaultReq) {
                    /* Master has default requirements for
                     * this slave, default has priority over
                     * current requirements.
                     */
                    master->reqs[i].nextReq =
                        master->reqs[i].defaultReq;
                } else {
                    /* Save current requirements as next */
                    master->reqs[i].nextReq =
                        master->reqs[i].currReq;
                }
            }

            master->reqs[i].currReq = tmpReq;

            /* Update slave setting */
            status = PmUpdateSlave(master->reqs[i].slave);
            /* if rom works correctly, status should be always ok */
            if (XST_SUCCESS != status) {
                PmDbg("ERROR setting slave node %s\n",
                      PmStrNode(master->reqs[i].slave->node.nodeId));
                break;
            }
        }
    }

    return status;
}
Beispiel #13
0
/**
 * PmSramFsmHandler() - Sram FSM handler, performs transition actions
 * @slave       Slave whose state should be changed
 * @nextState   State the slave should enter
 *
 * @return      Status of performing transition action
 */
static int PmSramFsmHandler(PmSlave* const slave, const PmStateId nextState)
{
	int status = XST_PM_INTERNAL;
	PmSlaveSram* sram = (PmSlaveSram*)slave->node.derived;

	switch (slave->node.currState) {
	case PM_SRAM_STATE_ON:
		if (PM_SRAM_STATE_RET == nextState) {
			/* ON -> RET */
			XPfw_RMW32(sram->retCtrlAddr, sram->retCtrlMask,
				   sram->retCtrlMask);
			status = sram->PwrDn();
		} else if (PM_SRAM_STATE_OFF == nextState) {
			/* ON -> OFF*/
			XPfw_RMW32(sram->retCtrlAddr, sram->retCtrlMask,
				   ~sram->retCtrlMask);
			status = sram->PwrDn();
		} else {
			status = XST_NO_FEATURE;
		}
		break;
	case PM_SRAM_STATE_RET:
		if (PM_SRAM_STATE_ON == nextState) {
			/* RET -> ON */
			status = sram->PwrUp();
		} else if (PM_SRAM_STATE_OFF == nextState) {
			/* RET -> OFF */
			XPfw_RMW32(sram->retCtrlAddr, sram->retCtrlMask,
				   ~sram->retCtrlMask);
			status = sram->PwrDn();
		} else {
			status = XST_NO_FEATURE;
		}
		break;
	case PM_SRAM_STATE_OFF:
		if (PM_SRAM_STATE_ON == nextState) {
			/* OFF -> ON */
			status = sram->PwrUp();
		} else {
			status = XST_NO_FEATURE;
		}
		break;
	default:
		status = XST_PM_INTERNAL;
		PmDbg("ERROR: Unknown SRAM state #%d\n", slave->node.currState);
		break;
	}

	if (XST_SUCCESS == status) {
		PmNodeUpdateCurrState(&slave->node, nextState);
	}

	return status;
}
Beispiel #14
0
/**
 * PmRequirementCancelScheduled() - Called when master aborts suspend, to cancel
 * scheduled requirements (slave capabilities requests)
 * @master  Master whose scheduled requests should be cancelled
 */
void PmRequirementCancelScheduled(const PmMaster* const master)
{
    PmRequirementId i;

    for (i = 0; i < master->reqsCnt; i++) {
        if (master->reqs[i].currReq != master->reqs[i].nextReq) {
            /* Drop the scheduled request by making it constant */
            PmDbg("%s\n",
                  PmStrNode(master->reqs[i].slave->node.nodeId));
            master->reqs[i].nextReq = master->reqs[i].currReq;
        }
    }
}
Beispiel #15
0
/**
 * PmHasAwakeChild() - Check whether power node has awake children
 * @power       Pointer to PmPower object to be checked
 *
 * Function checks whether any child of the power provided as argument stops
 * power from being turned off. In the case of processor or power child, that
 * can be checked by inspecting currState value. For slaves, that is not the
 * case, as slave can be in non-off state just because the off state is entered
 * when power is turned off. This is the case when power parent is common for
 * multiple nodes. Therefore, slave does not block power from turning off if
 * it is unused and not in lowest power state.
 *
 * @return      True if it has a child that is not off
 */
static bool PmHasAwakeChild(const PmPower* const power)
{
	u32 i;
	bool hasAwakeChild = false;

	for (i = 0U; i < power->childCnt; i++) {
		if (false == PmChildIsInLowestPowerState(power->children[i])) {
			hasAwakeChild = true;
			PmDbg("%s\n", PmStrNode(power->children[i]->nodeId));
			break;
		}
	}

	return hasAwakeChild;
}
Beispiel #16
0
/**
 * PmEnableProxyWake() - Enable scheduled wake-up sources in GIC Proxy
 * @master  Pointer to master whose scheduled wake-up sources should be enabled
 *
 * When FPD is powered down, wake-up sources should be enabled in GIC Proxy,
 * if APU's primary processor is gently put into a sleep. If APU is forced to
 * power down, this function will return without enabling GIC Proxy, because
 * after forced power down the processor can only be woken-up by an explicit
 * wake-up request through PM API. The check whether the processor is in sleep
 * state is performed in this function and not in pm_power from where this
 * function is called in order to keep pm_power independent from (not-aware of)
 * processor states.
 */
void PmEnableProxyWake(PmMaster* const master)
{
    u32 i;

    if (master->procs->node.currState != PM_PROC_STATE_SLEEP) {
        goto done;
    }

    PmDbg("%s\n", PmStrNode(master->procs->node.nodeId));

    for (i = 0; i < master->reqsCnt; i++) {
        if (master->reqs[i].info & PM_MASTER_WAKEUP_REQ_MASK) {
            PmSlaveWakeEnable(master->reqs[i].slave);
        }
    }

done:
    return;
}