diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_common.h b/lib/sw_apps/zynqmp_pmufw/src/pm_common.h index 8f39d350..0936a9c1 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_common.h +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_common.h @@ -77,6 +77,9 @@ typedef u32 (*const PmTranHandler)(void); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define BIT0(x) (x & 1U) +#define TO_ACK_CB(ack, status) \ + ((REQUEST_ACK_CB_STANDARD == (ack)) || \ + ((REQUEST_ACK_CB_ERROR == (ack)) && (XST_SUCCESS != (status)))) /* All WFI bitfields in GPI2 */ #define PMU_LOCAL_GPI2_ENABLE_ALL_PWRDN_REQ_MASK \ diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_core.c b/lib/sw_apps/zynqmp_pmufw/src/pm_core.c index 5d28ab00..899480eb 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_core.c +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_core.c @@ -121,21 +121,48 @@ static void PmRequestSuspend(const PmMaster *const master, const u32 latency, const u32 state) { - PmProc* proc = PmGetProcOfOtherMaster(master, node); + int status; + PmProc* proc; PmDbg("(%s, %s, %d, %d)\n", PmStrNode(node), PmStrAck(ack), latency, state); - if (NULL == proc) { - PmDbg("ERROR processor not found by node %d\n", node); - PmProcessAckRequest(ack, master, node, XST_INVALID_PARAM, 0); + if (REQUEST_ACK_BLOCKING == ack) { + PmDbg("ERROR: invalid acknowledge REQUEST_ACK_BLOCKING\n"); + status = XST_INVALID_PARAM; goto done; } - PmInitSuspendCb(proc->master, node, 0, 0, 0, 0); + proc = PmGetProcOfOtherMaster(master, node); + if (NULL == proc) { + PmDbg("ERROR: irregular node %s\n", PmStrNode(node)); + status = XST_INVALID_PARAM; + goto done; + } + + if (false == PmCanRequestSuspend(master, proc->master)) { + PmDbg("ERROR: %s not allowed to request suspend of %s\n", + PmStrNode(master->procs->node.nodeId), + PmStrNode(proc->node.nodeId)); + status = XST_PM_NO_ACCESS; + goto done; + } + + PmInitSuspendCb(proc->master, node, SUSPEND_REASON_PU_REQ, latency, + state, MAX_LATENCY); + /* + * Suspend has been successfully requested, but the requested PU now + * needs to initiate its own self suspend. Remember to acknowledge to + * the requestor when: 1. PU gets powered down, 2. PU aborts suspend, + * 3. PU does not respond to the request (timeout). + */ + status = PmRememberSuspendRequest(master, proc->master, ack); done: - return; + if (XST_SUCCESS != status) { + /* Something went wrong, acknowledge immediatelly */ + PmProcessAckRequest(ack, master, node, status, 0); + } } /** diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_defs.h b/lib/sw_apps/zynqmp_pmufw/src/pm_defs.h index 76b40256..c3b3f3a4 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_defs.h +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_defs.h @@ -157,5 +157,6 @@ #define XST_PM_NO_ACCESS 2002L #define XST_PM_INVALID_NODE 2003L #define XST_PM_DOUBLE_REQ 2004L +#define XST_PM_ABORT_SUSPEND 2005L #endif diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_master.c b/lib/sw_apps/zynqmp_pmufw/src/pm_master.c index f7c679e2..c6c64f7e 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_master.c +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_master.c @@ -41,6 +41,7 @@ #include "pm_sram.h" #include "pm_usb.h" #include "pm_periph.h" +#include "pm_callbacks.h" #include "ipi_buffer.h" /* Requirement of APU master */ @@ -258,6 +259,27 @@ static const PmMaster *const pmAllMasters[] = { &pmMasterRpu1_g, }; +/* + * Content of the array should be filled with information from PCW. + * If a master has a priviledge to request some other master's suspend, the + * reqMst/respMst pair has to be defined in array below. If the pair does not + * exist, it will be considered that the requestor is not allowed to initiate + * suspend of the target master. + */ +static PmSuspendRequest pmSuspRequests[] = { + { + .reqMst = &pmMasterApu_g, + .respMst = &pmMasterRpu0_g, + .flags = 0U, + .ackReq = 0U, + }, { + .reqMst = &pmMasterRpu0_g, + .respMst = &pmMasterApu_g, + .flags = 0U, + .ackReq = 0U, + }, +}; + /** * PmRequirementSchedule() - Schedule requirements of the master for slave. * Slave state will be updated according to the @@ -752,6 +774,134 @@ static void PmWakeUpDisableAll(PmMaster* const master) } } +/** + * PmCanRequestSuspend() - Check whether master is privileged to request another + * master to suspend + * @reqMaster Master which requests another master to suspend + * @respMaster Master whose suspend is requested and which is extected to + * response to the request by initiating its own self suspend + * + * @return Check result + * - True if master has privilege to request suspend + * - False if master has no privilege + */ +bool PmCanRequestSuspend(const PmMaster* const reqMaster, + const PmMaster* const respMaster) +{ + u32 i; + bool hasPrivilege = false; + + for (i = 0U; i < ARRAY_SIZE(pmSuspRequests); i++) { + if ((reqMaster == pmSuspRequests[i].reqMst) && + (respMaster == pmSuspRequests[i].respMst)) { + hasPrivilege = true; + break; + } + } + + return hasPrivilege; +} + +/** + * PmIsRequestedToSuspend() - Check whether the master is requested from some + * other master to suspend + * @master Master to check for + * + * @return Check result + * - True if master is requested to suspend + * - False if no other master has requested this master to suspend + */ +bool PmIsRequestedToSuspend(const PmMaster* const master) +{ + u32 i; + bool requested = false; + + for (i = 0U; i < ARRAY_SIZE(pmSuspRequests); i++) { + if ((master == pmSuspRequests[i].respMst) && + (0U != (PM_REQUESTED_SUSPEND & pmSuspRequests[i].flags))) { + requested = true; + break; + } + } + + return requested; +} + +/** + * PmRememberSuspendRequest() - Remembers the request suspend to acknowledge + * @reqMaster Master which requested suspend + * @respMaster Master whose suspend is requested and which should answer + * @ack FIXME: missing coumentation + * + * @return Status of the operation of remembering the requested acknowledge + */ +int PmRememberSuspendRequest(const PmMaster* const reqMaster, + const PmMaster* const respMaster, + const u32 ack) +{ + u32 i; + int status; + + /* + * Assume failure, which will be returned if reqMaster/respMaster pair + * is not regular. + */ + status = XST_FAILURE; + + for (i = 0U; i < ARRAY_SIZE(pmSuspRequests); i++) { + if ((reqMaster == pmSuspRequests[i].reqMst) && + (respMaster == pmSuspRequests[i].respMst)) { + if ((REQUEST_ACK_CB_STANDARD == ack) || + (REQUEST_ACK_CB_ERROR == ack)) { + pmSuspRequests[i].ackReq = ack; + pmSuspRequests[i].flags |= PM_REQUESTED_SUSPEND; + status = XST_SUCCESS; + } else { + status = XST_PM_INTERNAL; + } + break; + } + } + + return status; +} + +/** + * PmMasterSuspendAck() - Acknowledge to the suspend request of another + * master + * @respMaster Master which is responding to the suspend request + * @response FIXME: Missing doc + */ +int PmMasterSuspendAck(const PmMaster* const respMaster, + const int response) +{ + u32 i; + int status; + + /* + * Assume to return failure, in case when there was no request to + * suspend + */ + status = XST_FAILURE; + + for (i = 0U; i < ARRAY_SIZE(pmSuspRequests); i++) { + if ((respMaster == pmSuspRequests[i].respMst) && + (0U != (PM_REQUESTED_SUSPEND & pmSuspRequests[i].flags))) { + if (TO_ACK_CB(pmSuspRequests[i].ackReq, response)) { + PmAcknowledgeCb(pmSuspRequests[i].reqMst, + pmSuspRequests[i].respMst->procs->node.nodeId, + response, + pmSuspRequests[i].respMst->procs->node.currState); + } + pmSuspRequests[i].flags &= ~PM_REQUESTED_SUSPEND; + pmSuspRequests[i].ackReq = 0U; + status = XST_SUCCESS; + } + } + + return status; +} + /** * PmMasterNotify() - Notify master channel of a state change in its primary processor * @master Pointer to master object which needs to be notified diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_master.h b/lib/sw_apps/zynqmp_pmufw/src/pm_master.h index 1c067ee0..0b4711af 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_master.h +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_master.h @@ -85,6 +85,9 @@ typedef struct PmMaster PmMaster; #define PM_MASTER_WAKEUP_REQ_MASK 0x1U #define PM_MASTER_USING_SLAVE_MASK 0x2U +/* Suspend request related */ +#define PM_REQUESTED_SUSPEND 0x1U + /********************************************************************* * Structure definitions ********************************************************************/ @@ -141,6 +144,22 @@ typedef struct PmMaster { const PmRequirementId reqsCnt; } PmMaster; +/** + * PmSuspendRequest() - For tracking information about which master can/has + * requested which master to suspend. + * @reqMst Master which is priviledged to request suspend of respMst + * @respMst Master which is requested to suspend and which should initiate + * its own self suspend + * @flags Flags storing information about the actual request + * @ackReq Acknowledge argument provided with the request suspend call + */ +typedef struct { + const PmMaster* reqMst; + const PmMaster* respMst; + u8 flags; + u32 ackReq; +} PmSuspendRequest; + /********************************************************************* * Global data declarations ********************************************************************/ @@ -179,4 +198,16 @@ void PmEnableAllMasterIpis(void); /* Call when FPD goes down to enable GIC Proxy interrupts */ void PmEnableProxyWake(PmMaster* const master); +bool PmCanRequestSuspend(const PmMaster* const reqMaster, + const PmMaster* const respMaster); +bool PmIsRequestedToSuspend(const PmMaster* const master); + +int PmRememberSuspendRequest(const PmMaster* const reqMaster, + const PmMaster* const respMaster, + const u32 ack); + +int PmMasterSuspendAck(const PmMaster* const respMaster, + const int response); + + #endif diff --git a/lib/sw_apps/zynqmp_pmufw/src/pm_proc.c b/lib/sw_apps/zynqmp_pmufw/src/pm_proc.c index 698d8321..543292aa 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/pm_proc.c +++ b/lib/sw_apps/zynqmp_pmufw/src/pm_proc.c @@ -264,6 +264,14 @@ static int PmProcTrSuspendToSleep(PmProc* const proc) * scheduled requests for after primary processor goes to sleep. */ status = PmMasterNotify(proc->master, PM_PROC_EVENT_SLEEP); + + if (true == PmIsRequestedToSuspend(proc->master)) { + /* + * Acknowledge to the requestor of the suspend that + * suspend is completed. + */ + status = PmMasterSuspendAck(proc->master, status); + } } DISABLE_WFI(proc->wfiEnableMask); ENABLE_WAKE(proc->wakeEnableMask); @@ -367,6 +375,11 @@ int PmProcFsm(PmProc* const proc, const PmProcEvent event) case PM_PROC_EVENT_ABORT_SUSPEND: if (PM_PROC_STATE_SUSPENDING == currState) { status = PmProcTrSuspendToActive(proc); + } else if (PM_PROC_STATE_ACTIVE == currState) { + /* Processor aborting request to suspend */ + status = PmMasterSuspendAck(proc->master, + XST_PM_ABORT_SUSPEND); + } else { } break; case PM_PROC_EVENT_SLEEP: diff --git a/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h b/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h index f67a93b9..acf97bbb 100644 --- a/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h +++ b/lib/sw_apps/zynqmp_pmufw/src/xpfw_version.h @@ -1,4 +1,4 @@ #ifndef ZYNQMP_XPFW_VERSION__H_ #define ZYNQMP_XPFW_VERSION__H_ - #define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-31-g8df039867de7" + #define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-32-g0e7cb08c2e45" #endif