PMUFW: PM: PLL: Added PLL slaves
-Added PLL nodes (PLLs are PM slaves) -Implemented PLL's FSM in pm_pll.h/c -Added PmRequirement structures for APU and RPU_0, both can request any PLL for usage -Implemented saving of FPD PLLs' context and powering down FPD PLLs before FPD gets powered down (this is PLL suspend) -Implemented restoring of PLL states when PLL is needed for usage if FPD has been powered down (this is PLL resume) Signed-off-by: Mirela Simonovic <mirela.simonovic@aggios.com> Acked-by: Jyotheeswar Reddy Mutthareddyvari <jyothee@xilinx.com>
This commit is contained in:
parent
568b6a1494
commit
5ad6dc1280
11 changed files with 636 additions and 4 deletions
|
@ -99,6 +99,16 @@ const char* PmStrNode(const u32 node)
|
|||
return "NODE_TTC_0";
|
||||
case NODE_SATA:
|
||||
return "NODE_SATA";
|
||||
case NODE_APLL:
|
||||
return "NODE_APLL";
|
||||
case NODE_VPLL:
|
||||
return "NODE_VPLL";
|
||||
case NODE_DPLL:
|
||||
return "NODE_DPLL";
|
||||
case NODE_RPLL:
|
||||
return "NODE_RPLL";
|
||||
case NODE_IOPLL:
|
||||
return "NODE_IOPLL";
|
||||
default:
|
||||
return "ERROR_NODE";
|
||||
}
|
||||
|
|
|
@ -124,9 +124,14 @@
|
|||
#define NODE_USB_1 23U
|
||||
#define NODE_TTC_0 24U
|
||||
#define NODE_SATA 25U
|
||||
#define NODE_APLL 26U
|
||||
#define NODE_VPLL 27U
|
||||
#define NODE_DPLL 28U
|
||||
#define NODE_RPLL 29U
|
||||
#define NODE_IOPLL 30U
|
||||
|
||||
#define NODE_MIN NODE_APU
|
||||
#define NODE_MAX NODE_SATA
|
||||
#define NODE_MAX NODE_IOPLL
|
||||
|
||||
/* Request acknowledge argument values */
|
||||
#define REQUEST_ACK_NO 1U
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "pm_defs.h"
|
||||
#include "pm_sram.h"
|
||||
#include "pm_usb.h"
|
||||
#include "pm_pll.h"
|
||||
#include "pm_periph.h"
|
||||
#include "pm_callbacks.h"
|
||||
#include "ipi_buffer.h"
|
||||
|
@ -118,6 +119,46 @@ PmRequirement pmApuReq_g[PM_MASTER_APU_SLAVE_MAX] = {
|
|||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_APU_SLAVE_APLL] = {
|
||||
.slave = &pmSlaveApll_g.slv,
|
||||
.requestor = &pmMasterApu_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_APU_SLAVE_VPLL] = {
|
||||
.slave = &pmSlaveVpll_g.slv,
|
||||
.requestor = &pmMasterApu_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_APU_SLAVE_DPLL] = {
|
||||
.slave = &pmSlaveDpll_g.slv,
|
||||
.requestor = &pmMasterApu_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_APU_SLAVE_RPLL] = {
|
||||
.slave = &pmSlaveRpll_g.slv,
|
||||
.requestor = &pmMasterApu_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_APU_SLAVE_IOPLL] = {
|
||||
.slave = &pmSlaveIOpll_g.slv,
|
||||
.requestor = &pmMasterApu_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
};
|
||||
|
||||
/* Requirement of RPU_0 master */
|
||||
|
@ -218,6 +259,46 @@ PmRequirement pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_MAX] = {
|
|||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_RPU_0_SLAVE_APLL] = {
|
||||
.slave = &pmSlaveApll_g.slv,
|
||||
.requestor = &pmMasterRpu0_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_RPU_0_SLAVE_VPLL] = {
|
||||
.slave = &pmSlaveVpll_g.slv,
|
||||
.requestor = &pmMasterRpu0_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_RPU_0_SLAVE_DPLL] = {
|
||||
.slave = &pmSlaveDpll_g.slv,
|
||||
.requestor = &pmMasterRpu0_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_RPU_0_SLAVE_RPLL] = {
|
||||
.slave = &pmSlaveRpll_g.slv,
|
||||
.requestor = &pmMasterRpu0_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
[PM_MASTER_RPU_0_SLAVE_IOPLL] = {
|
||||
.slave = &pmSlaveIOpll_g.slv,
|
||||
.requestor = &pmMasterRpu0_g,
|
||||
.info = 0U,
|
||||
.defaultReq = 0U,
|
||||
.currReq = 0U,
|
||||
.nextReq = 0U,
|
||||
},
|
||||
};
|
||||
|
||||
PmMaster pmMasterApu_g = {
|
||||
|
|
|
@ -64,7 +64,13 @@ typedef struct PmMaster PmMaster;
|
|||
#define PM_MASTER_APU_SLAVE_USB1 6U
|
||||
#define PM_MASTER_APU_SLAVE_TTC0 7U
|
||||
#define PM_MASTER_APU_SLAVE_SATA 8U
|
||||
#define PM_MASTER_APU_SLAVE_MAX 9U
|
||||
#define PM_MASTER_APU_SLAVE_APLL 9U
|
||||
#define PM_MASTER_APU_SLAVE_VPLL 10U
|
||||
#define PM_MASTER_APU_SLAVE_DPLL 11U
|
||||
#define PM_MASTER_APU_SLAVE_RPLL 12U
|
||||
#define PM_MASTER_APU_SLAVE_IOPLL 13U
|
||||
|
||||
#define PM_MASTER_APU_SLAVE_MAX 14U
|
||||
|
||||
/* Rpu0 slaves */
|
||||
#define PM_MASTER_RPU_0_SLAVE_TCM0A 0U
|
||||
|
@ -79,7 +85,13 @@ typedef struct PmMaster PmMaster;
|
|||
#define PM_MASTER_RPU_0_SLAVE_USB1 9U
|
||||
#define PM_MASTER_RPU_0_SLAVE_TTC0 10U
|
||||
#define PM_MASTER_RPU_0_SLAVE_SATA 11U
|
||||
#define PM_MASTER_RPU_0_SLAVE_MAX 12U
|
||||
#define PM_MASTER_RPU_0_SLAVE_APLL 12U
|
||||
#define PM_MASTER_RPU_0_SLAVE_VPLL 13U
|
||||
#define PM_MASTER_RPU_0_SLAVE_DPLL 14U
|
||||
#define PM_MASTER_RPU_0_SLAVE_RPLL 15U
|
||||
#define PM_MASTER_RPU_0_SLAVE_IOPLL 16U
|
||||
|
||||
#define PM_MASTER_RPU_0_SLAVE_MAX 17U
|
||||
|
||||
/* Pm Master request info masks */
|
||||
#define PM_MASTER_WAKEUP_REQ_MASK 0x1U
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "pm_sram.h"
|
||||
#include "pm_usb.h"
|
||||
#include "pm_periph.h"
|
||||
#include "pm_pll.h"
|
||||
|
||||
static PmNode* const pmNodes[NODE_MAX] = {
|
||||
&pmApuProcs_g[PM_PROC_APU_0].node,
|
||||
|
@ -63,6 +64,11 @@ static PmNode* const pmNodes[NODE_MAX] = {
|
|||
&pmSlaveUsb1_g.slv.node,
|
||||
&pmSlaveTtc0_g.slv.node,
|
||||
&pmSlaveSata_g.slv.node,
|
||||
&pmSlaveApll_g.slv.node,
|
||||
&pmSlaveVpll_g.slv.node,
|
||||
&pmSlaveDpll_g.slv.node,
|
||||
&pmSlaveRpll_g.slv.node,
|
||||
&pmSlaveIOpll_g.slv.node,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef int (*const PmNodeTranHandler)(PmNode* const nodePtr);
|
|||
#define PM_TYPE_GPU_PP (PM_TYPE_SLAVE + 2U)
|
||||
#define PM_TYPE_TTC (PM_TYPE_SLAVE + 3U)
|
||||
#define PM_TYPE_SATA (PM_TYPE_SLAVE + 4U)
|
||||
#define PM_TYPE_PLL (PM_TYPE_SLAVE + 5U)
|
||||
|
||||
#define IS_PROC(type) (PM_TYPE_PROC == type)
|
||||
|
||||
|
|
370
lib/sw_apps/zynqmp_pmufw/src/pm_pll.c
Normal file
370
lib/sw_apps/zynqmp_pmufw/src/pm_pll.c
Normal file
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright (C) 2014 - 2015 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* Use of the Software is limited solely to applications:
|
||||
* (a) running on a Xilinx device, or
|
||||
* (b) that interact with a Xilinx device through a bus or interconnect.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of the Xilinx shall not be used
|
||||
* in advertising or otherwise to promote the sale, use or other dealings in
|
||||
* this Software without prior written authorization from Xilinx.
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* Contains:
|
||||
* - PLL slave implementation
|
||||
* - PLL slave's FSM implementation - only tracks the PLL usage status
|
||||
* (used/unused).
|
||||
* - Functions for saving and restoring PLLs' context
|
||||
*
|
||||
* Note: PMU does not control states of PLLs. When none of FPD PLLs
|
||||
* is used and FPD is going to be powered down, PMU saves context of
|
||||
* PLLs in FPD and asserts their reset. After powering up FPD, PMU
|
||||
* restores the state of PLL based on saved context only when PLL is
|
||||
* needed for the use.
|
||||
*********************************************************************/
|
||||
|
||||
#include "pm_pll.h"
|
||||
#include "pm_master.h"
|
||||
#include "pm_power.h"
|
||||
#include "crf_apb.h"
|
||||
#include "crl_apb.h"
|
||||
#include "xpfw_util.h"
|
||||
|
||||
/* PLL states */
|
||||
static const u32 pmPllStates[PM_PLL_STATE_MAX] = {
|
||||
[PM_PLL_STATE_UNUSED] = 0U,
|
||||
[PM_PLL_STATE_USED] = PM_CAP_ACCESS | PM_CAP_POWER,
|
||||
};
|
||||
|
||||
/* PLL transition table (from which to which state PLL can transit) */
|
||||
static const PmStateTran pmPllTransitions[] = {
|
||||
{
|
||||
.fromState = PM_PLL_STATE_USED,
|
||||
.toState = PM_PLL_STATE_UNUSED,
|
||||
}, {
|
||||
.fromState = PM_PLL_STATE_UNUSED,
|
||||
.toState = PM_PLL_STATE_USED,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* PmPllBypassAndReset() - Bypass and reset/power down a PLL
|
||||
* @pll Pointer to a Pll to be bypassed/reset
|
||||
*/
|
||||
static void PmPllBypassAndReset(PmSlavePll* const pll)
|
||||
{
|
||||
/* Bypass PLL before putting it into the reset */
|
||||
XPfw_RMW32(pll->addr + PM_PLL_CTRL_OFFSET, PM_PLL_CTRL_BYPASS_MASK,
|
||||
PM_PLL_CTRL_BYPASS_MASK);
|
||||
|
||||
/* Power down PLL (= reset PLL) */
|
||||
XPfw_RMW32(pll->addr + PM_PLL_CTRL_OFFSET, PM_PLL_CTRL_RESET_MASK,
|
||||
PM_PLL_CTRL_RESET_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* PmPllSuspend() - Save context of PLL and power it down (reset)
|
||||
* @pll Pointer to a Pll to be suspended
|
||||
*/
|
||||
static void PmPllSuspend(PmSlavePll* const pll)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
/* Save register setting */
|
||||
pll->context.ctrl = XPfw_Read32(pll->addr + PM_PLL_CTRL_OFFSET);
|
||||
pll->context.cfg = XPfw_Read32(pll->addr + PM_PLL_CFG_OFFSET);
|
||||
pll->context.frac = XPfw_Read32(pll->addr + PM_PLL_FRAC_OFFSET);
|
||||
pll->context.toCtrl = XPfw_Read32(pll->toCtrlAddr);
|
||||
pll->context.saved = true;
|
||||
|
||||
val = XPfw_Read32(pll->addr + PM_PLL_CTRL_OFFSET);
|
||||
/* If PLL is not already in reset, bypass it and put in reset/pwrdn */
|
||||
if (0U == (val & PM_PLL_CTRL_RESET_MASK)) {
|
||||
PmPllBypassAndReset(pll);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PmPllResume() - Restore PLL context
|
||||
* @pll Pll whose context should be restored
|
||||
*
|
||||
* @return Status of resume:
|
||||
* - XST_SUCCESS if resumed correctly
|
||||
* - XST_FAILURE if resume failed (if PLL failed to lock)
|
||||
*/
|
||||
static int PmPllResume(PmSlavePll* const pll)
|
||||
{
|
||||
int status = XST_SUCCESS;
|
||||
|
||||
if (true == pll->context.saved) {
|
||||
/* Restore register values with reset and bypass asserted */
|
||||
XPfw_Write32(pll->addr + PM_PLL_CTRL_OFFSET, pll->context.ctrl |
|
||||
PM_PLL_CTRL_RESET_MASK | PM_PLL_CTRL_BYPASS_MASK);
|
||||
XPfw_Write32(pll->addr + PM_PLL_CFG_OFFSET, pll->context.cfg);
|
||||
XPfw_Write32(pll->addr + PM_PLL_FRAC_OFFSET, pll->context.frac);
|
||||
XPfw_Write32(pll->toCtrlAddr, pll->context.toCtrl);
|
||||
pll->context.saved = false;
|
||||
}
|
||||
|
||||
if (0U != (PM_PLL_CTRL_RESET_MASK & pll->context.ctrl)) {
|
||||
/* By saved/init configuration PLL is in reset, leave it as is */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Release reset */
|
||||
XPfw_RMW32(pll->addr + PM_PLL_CTRL_OFFSET, PM_PLL_CTRL_RESET_MASK,
|
||||
~PM_PLL_CTRL_RESET_MASK);
|
||||
/* Poll status register for the lock */
|
||||
status = XPfw_UtilPollForMask(pll->statusAddr, pll->lockMask,
|
||||
PM_PLL_LOCK_TIMEOUT);
|
||||
if (XST_SUCCESS != status) {
|
||||
/* Failed to lock PLL - assert reset and return */
|
||||
XPfw_RMW32(pll->addr + PM_PLL_CTRL_OFFSET,
|
||||
PM_PLL_CTRL_RESET_MASK, PM_PLL_CTRL_RESET_MASK);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* PLL is bypassed here (done by the reset) */
|
||||
if (0U == (PM_PLL_CTRL_BYPASS_MASK & pll->context.ctrl)) {
|
||||
/* According to saved context PLL should not be bypassed */
|
||||
XPfw_RMW32(pll->addr + PM_PLL_CTRL_OFFSET,
|
||||
PM_PLL_CTRL_BYPASS_MASK,
|
||||
~PM_PLL_CTRL_BYPASS_MASK);
|
||||
}
|
||||
|
||||
done:
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* PmPllFsmHandler() - PLL FSM handler
|
||||
* @slave Slave whose state should be changed
|
||||
* @nextState State the slave should enter
|
||||
*
|
||||
* @return Always XST_SUCCESS if FSM is implemented correctly
|
||||
*
|
||||
* Note: PLL FSM basically updates currState variable and restores PLL state
|
||||
* if needed. FSM transitions cannot fail.
|
||||
*/
|
||||
static int PmPllFsmHandler(PmSlave* const slave, const PmStateId nextState)
|
||||
{
|
||||
int status;
|
||||
PmSlavePll* pll = (PmSlavePll*)slave->node.derived;
|
||||
|
||||
switch (nextState) {
|
||||
case PM_PLL_STATE_USED:
|
||||
/* Resume the PLL */
|
||||
status = PmPllResume(pll);
|
||||
break;
|
||||
case PM_PLL_STATE_UNUSED:
|
||||
/* Bypassing and reseting PLL cannot fail */
|
||||
PmPllBypassAndReset(pll);
|
||||
status = XST_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
status = XST_PM_INTERNAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (XST_SUCCESS == status) {
|
||||
slave->node.currState = nextState;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* PLL FSM */
|
||||
static const PmSlaveFsm slavePllFsm = {
|
||||
.states = pmPllStates,
|
||||
.statesCnt = ARRAY_SIZE(pmPllStates),
|
||||
.trans = pmPllTransitions,
|
||||
.transCnt = ARRAY_SIZE(pmPllTransitions),
|
||||
.enterState = PmPllFsmHandler,
|
||||
};
|
||||
|
||||
/* APLL */
|
||||
static PmRequirement* const pmApllReqs[] = {
|
||||
&pmApuReq_g[PM_MASTER_APU_SLAVE_APLL],
|
||||
&pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_APLL],
|
||||
};
|
||||
|
||||
PmSlavePll pmSlaveApll_g = {
|
||||
.slv = {
|
||||
.node = {
|
||||
.derived = &pmSlaveApll_g,
|
||||
.nodeId = NODE_APLL,
|
||||
.typeId = PM_TYPE_PLL,
|
||||
.parent = &pmPowerDomainFpd_g,
|
||||
.ops = NULL,
|
||||
},
|
||||
.reqs = pmApllReqs,
|
||||
.reqsCnt = ARRAY_SIZE(pmApllReqs),
|
||||
.wake = NULL,
|
||||
.slvFsm = &slavePllFsm,
|
||||
},
|
||||
.context = {
|
||||
.saved = false,
|
||||
},
|
||||
.addr = CRF_APB_APLL_CTRL,
|
||||
.toCtrlAddr = CRF_APB_APLL_TO_LPD_CTRL,
|
||||
.statusAddr = CRF_APB_PLL_STATUS,
|
||||
.lockMask = CRF_APB_PLL_STATUS_APLL_LOCK_MASK,
|
||||
};
|
||||
|
||||
/* VPLL */
|
||||
static PmRequirement* const pmVpllReqs[] = {
|
||||
&pmApuReq_g[PM_MASTER_APU_SLAVE_VPLL],
|
||||
&pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_VPLL],
|
||||
};
|
||||
|
||||
PmSlavePll pmSlaveVpll_g = {
|
||||
.slv = {
|
||||
.node = {
|
||||
.derived = &pmSlaveVpll_g,
|
||||
.nodeId = NODE_VPLL,
|
||||
.typeId = PM_TYPE_PLL,
|
||||
.parent = &pmPowerDomainFpd_g,
|
||||
.ops = NULL,
|
||||
},
|
||||
.reqs = pmVpllReqs,
|
||||
.reqsCnt = ARRAY_SIZE(pmVpllReqs),
|
||||
.wake = NULL,
|
||||
.slvFsm = &slavePllFsm,
|
||||
},
|
||||
.context = {
|
||||
.saved = false,
|
||||
},
|
||||
.addr = CRF_APB_VPLL_CTRL,
|
||||
.toCtrlAddr = CRF_APB_VPLL_TO_LPD_CTRL,
|
||||
.statusAddr = CRF_APB_PLL_STATUS,
|
||||
.lockMask = CRF_APB_PLL_STATUS_VPLL_LOCK_MASK,
|
||||
};
|
||||
|
||||
/* DPLL */
|
||||
static PmRequirement* const pmDpllReqs[] = {
|
||||
&pmApuReq_g[PM_MASTER_APU_SLAVE_DPLL],
|
||||
&pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_DPLL],
|
||||
};
|
||||
|
||||
PmSlavePll pmSlaveDpll_g = {
|
||||
.slv = {
|
||||
.node = {
|
||||
.derived = &pmSlaveDpll_g,
|
||||
.nodeId = NODE_DPLL,
|
||||
.typeId = PM_TYPE_PLL,
|
||||
.parent = &pmPowerDomainFpd_g,
|
||||
.ops = NULL,
|
||||
},
|
||||
.reqs = pmDpllReqs,
|
||||
.reqsCnt = ARRAY_SIZE(pmDpllReqs),
|
||||
.wake = NULL,
|
||||
.slvFsm = &slavePllFsm,
|
||||
},
|
||||
.context = {
|
||||
.saved = false,
|
||||
},
|
||||
.addr = CRF_APB_DPLL_CTRL,
|
||||
.toCtrlAddr = CRF_APB_DPLL_TO_LPD_CTRL,
|
||||
.statusAddr = CRF_APB_PLL_STATUS,
|
||||
.lockMask = CRF_APB_PLL_STATUS_DPLL_LOCK_MASK,
|
||||
};
|
||||
|
||||
/* RPLL */
|
||||
static PmRequirement* const pmRpllReqs[] = {
|
||||
&pmApuReq_g[PM_MASTER_APU_SLAVE_RPLL],
|
||||
&pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_RPLL],
|
||||
};
|
||||
|
||||
PmSlavePll pmSlaveRpll_g = {
|
||||
.slv = {
|
||||
.node = {
|
||||
.derived = &pmSlaveRpll_g,
|
||||
.nodeId = NODE_RPLL,
|
||||
.typeId = PM_TYPE_PLL,
|
||||
.parent = NULL,
|
||||
.ops = NULL,
|
||||
},
|
||||
.reqs = pmRpllReqs,
|
||||
.reqsCnt = ARRAY_SIZE(pmRpllReqs),
|
||||
.wake = NULL,
|
||||
.slvFsm = &slavePllFsm,
|
||||
},
|
||||
.context = {
|
||||
.saved = false,
|
||||
},
|
||||
.addr = CRL_APB_RPLL_CTRL,
|
||||
.toCtrlAddr = CRL_APB_RPLL_TO_FPD_CTRL,
|
||||
.statusAddr = CRL_APB_PLL_STATUS,
|
||||
.lockMask = CRL_APB_PLL_STATUS_RPLL_LOCK_MASK,
|
||||
};
|
||||
|
||||
/* IOPLL */
|
||||
static PmRequirement* const pmIOpllReqs[] = {
|
||||
&pmApuReq_g[PM_MASTER_APU_SLAVE_IOPLL],
|
||||
&pmRpu0Req_g[PM_MASTER_RPU_0_SLAVE_IOPLL],
|
||||
};
|
||||
|
||||
PmSlavePll pmSlaveIOpll_g = {
|
||||
.slv = {
|
||||
.node = {
|
||||
.derived = &pmSlaveIOpll_g,
|
||||
.nodeId = NODE_IOPLL,
|
||||
.typeId = PM_TYPE_PLL,
|
||||
.parent = NULL,
|
||||
.ops = NULL,
|
||||
},
|
||||
.reqs = pmIOpllReqs,
|
||||
.reqsCnt = ARRAY_SIZE(pmIOpllReqs),
|
||||
.wake = NULL,
|
||||
.slvFsm = &slavePllFsm,
|
||||
},
|
||||
.context = {
|
||||
.saved = false,
|
||||
},
|
||||
.addr = CRL_APB_IOPLL_CTRL,
|
||||
.toCtrlAddr = CRL_APB_IOPLL_TO_FPD_CTRL,
|
||||
.statusAddr = CRL_APB_PLL_STATUS,
|
||||
.lockMask = CRL_APB_PLL_STATUS_IOPLL_LOCK_MASK,
|
||||
};
|
||||
|
||||
static PmSlavePll* const pmPlls[] = {
|
||||
&pmSlaveApll_g,
|
||||
&pmSlaveVpll_g,
|
||||
&pmSlaveDpll_g,
|
||||
&pmSlaveRpll_g,
|
||||
&pmSlaveIOpll_g,
|
||||
};
|
||||
|
||||
/**
|
||||
* PmPllSuspendAll() - Suspend all PLLs whose power parent is given as argument
|
||||
* @powerParent Power parent of PLLs to be suspended
|
||||
*/
|
||||
void PmPllSuspendAll(const PmPower* const powerParent)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
for (i = 0U; i < ARRAY_SIZE(pmPlls); i++) {
|
||||
if (powerParent == pmPlls[i]->slv.node.parent) {
|
||||
PmPllSuspend(pmPlls[i]);
|
||||
}
|
||||
}
|
||||
}
|
136
lib/sw_apps/zynqmp_pmufw/src/pm_pll.h
Normal file
136
lib/sw_apps/zynqmp_pmufw/src/pm_pll.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2014 - 2015 Xilinx, Inc. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* Use of the Software is limited solely to applications:
|
||||
* (a) running on a Xilinx device, or
|
||||
* (b) that interact with a Xilinx device through a bus or interconnect.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of the Xilinx shall not be used
|
||||
* in advertising or otherwise to promote the sale, use or other dealings in
|
||||
* this Software without prior written authorization from Xilinx.
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* Contains:
|
||||
* - PLL slave implementation
|
||||
* - Functions for saving and restoring PLLs' context
|
||||
*
|
||||
* Note: PMU does not control states of PLLs. When none of FPD PLLs
|
||||
* is used and FPD is going to be powered down, PMU saves context of
|
||||
* PLLs in FPD and asserts their reset. After powering up FPD, PMU
|
||||
* restores the state of PLL based on saved context.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef PM_PLL_H_
|
||||
#define PM_PLL_H_
|
||||
|
||||
#include "pm_slave.h"
|
||||
|
||||
/*********************************************************************
|
||||
* Macros
|
||||
********************************************************************/
|
||||
/* PLL states: */
|
||||
/*
|
||||
* PLL is not used by any master, so it can be powered down and it's power
|
||||
* parent can be powered down as well.
|
||||
*/
|
||||
#define PM_PLL_STATE_UNUSED 0U
|
||||
/* PLL is used by at least one master which is controlling state of PLL */
|
||||
#define PM_PLL_STATE_USED 1U
|
||||
#define PM_PLL_STATE_MAX 2U
|
||||
|
||||
/* Register offsets (in regard to PLL's base address of control registers) */
|
||||
#define PM_PLL_CTRL_OFFSET 0x0U
|
||||
#define PM_PLL_CFG_OFFSET 0x4U
|
||||
#define PM_PLL_FRAC_OFFSET 0x8U
|
||||
|
||||
/* Masks of bitfields in PLL's control register */
|
||||
#define PM_PLL_CTRL_RESET_MASK 0x1U
|
||||
#define PM_PLL_CTRL_BYPASS_MASK 0x8U
|
||||
|
||||
/* Configurable: timeout period when waiting for PLL to lock */
|
||||
#define PM_PLL_LOCK_TIMEOUT 0x10000U
|
||||
/*********************************************************************
|
||||
* Structure definitions
|
||||
********************************************************************/
|
||||
/**
|
||||
* PmPllContext - Structure for saving context of PLL registers.
|
||||
* Contains variable to store default content of:
|
||||
* @ctrl Control register
|
||||
* @cfg Configuration register
|
||||
* @frac Fractional control register
|
||||
* @toCtrl Control for a cross domain (a divisor)
|
||||
* @saved Flag stating are variables of this structure containing values
|
||||
* to be restored or not
|
||||
*
|
||||
* Note: context of the PLL is saved just before power-parent of PLL gets
|
||||
* powered down (FPD for example) and then the 'saved' flag is set to true.
|
||||
* In order to enter PM_PLL_STATE_USED state, PLL must have valid context,
|
||||
* meaning the 'saved' flag must be false. Upon initialization (as long as
|
||||
* power-parent does not get powered down), all data except 'saved' is
|
||||
* invalid/not-initialized (basically 'saved' flag also states do fields of
|
||||
* this structure have valid values or not).
|
||||
*/
|
||||
typedef struct PmPllContext {
|
||||
u32 ctrl;
|
||||
u32 cfg;
|
||||
u32 frac;
|
||||
u32 toCtrl;
|
||||
bool saved;
|
||||
} PmPllContext;
|
||||
|
||||
/**
|
||||
* PmSlavePll - Structure used for Pll slave
|
||||
* @slv Base slave structure
|
||||
* @context Data to store context of the PLL - if after boot PLL has no
|
||||
* context, it should not be initially locked by PMU, but by a
|
||||
* master. To inform PMU that initially PLL has no context, this
|
||||
* field should be initialized with the PM_PLL_CTRL_RESET_MASK
|
||||
* set, statically or through PCW.
|
||||
* @addr Base address of the PLL's control registers
|
||||
* @toCtrlAddr Absolute address of cross-domain control register
|
||||
* @statusAddr Address of the PLL's status register
|
||||
* @lockMask Mask of the lock in status register
|
||||
*/
|
||||
typedef struct PmSlavePll {
|
||||
PmSlave slv;
|
||||
PmPllContext context;
|
||||
const u32 addr;
|
||||
const u32 toCtrlAddr;
|
||||
const u32 statusAddr;
|
||||
const u32 lockMask;
|
||||
} PmSlavePll;
|
||||
|
||||
/*********************************************************************
|
||||
* Global data declarations
|
||||
********************************************************************/
|
||||
extern PmSlavePll pmSlaveApll_g;
|
||||
extern PmSlavePll pmSlaveDpll_g;
|
||||
extern PmSlavePll pmSlaveVpll_g;
|
||||
extern PmSlavePll pmSlaveRpll_g;
|
||||
extern PmSlavePll pmSlaveIOpll_g;
|
||||
|
||||
/*********************************************************************
|
||||
* Function declarations
|
||||
********************************************************************/
|
||||
void PmPllSuspendAll(const PmPower* const powerParent);
|
||||
|
||||
#endif
|
|
@ -39,6 +39,7 @@
|
|||
#include "pm_master.h"
|
||||
#include "pm_sram.h"
|
||||
#include "pm_periph.h"
|
||||
#include "pm_pll.h"
|
||||
#include "xpfw_rom_interface.h"
|
||||
#include "crf_apb.h"
|
||||
|
||||
|
@ -105,6 +106,7 @@ static int PmPowerDownFpd(void)
|
|||
int status = XpbrRstFpdHandler();
|
||||
|
||||
if (XST_SUCCESS == status) {
|
||||
PmPllSuspendAll(&pmPowerDomainFpd_g);
|
||||
PmCrfSaveContext();
|
||||
status = XpbrPwrDnFpdHandler();
|
||||
/*
|
||||
|
@ -235,6 +237,9 @@ static PmNode* pmFpdChildren[] = {
|
|||
&pmPowerIslandApu_g.node,
|
||||
&pmSlaveL2_g.slv.node,
|
||||
&pmSlaveSata_g.slv.node,
|
||||
&pmSlaveApll_g.slv.node,
|
||||
&pmSlaveVpll_g.slv.node,
|
||||
&pmSlaveDpll_g.slv.node,
|
||||
};
|
||||
|
||||
/* Operations for the Rpu power island */
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "pm_sram.h"
|
||||
#include "pm_usb.h"
|
||||
#include "pm_periph.h"
|
||||
#include "pm_pll.h"
|
||||
#include "pm_power.h"
|
||||
#include "lpd_slcr.h"
|
||||
|
||||
|
@ -82,6 +83,11 @@ static PmSlave* const pmSlaves[] = {
|
|||
&pmSlaveUsb1_g.slv,
|
||||
&pmSlaveTtc0_g.slv,
|
||||
&pmSlaveSata_g.slv,
|
||||
&pmSlaveApll_g.slv,
|
||||
&pmSlaveVpll_g.slv,
|
||||
&pmSlaveDpll_g.slv,
|
||||
&pmSlaveRpll_g.slv,
|
||||
&pmSlaveIOpll_g.slv,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef ZYNQMP_XPFW_VERSION__H_
|
||||
#define ZYNQMP_XPFW_VERSION__H_
|
||||
#define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-40-ge46a2aec66e8"
|
||||
#define ZYNQMP_XPFW_VERSION "2015.1-swbeta2-41-g884008482155"
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue