Power Optimization during Boot Up
This page discusses techniques to optimize power at FSBL stage, particularly applicable for applications that don't use a runtime PM stack.
Table of Contents
Introduction
There are different software components involved in the boot flow for Zynq Ultrascale+ MPSoC devices. These include First Stage Boot Loader (FSBL), Platform Management Unit Firmware (PMUFW), APU Apps (ATF/U-Boot/Linux), RPU Apps (FreeRTOS).
Power Management in PMUFW is an on-demand service which responds to IPI based requests from client processors. Xilinx provides a client library XilPM for bare-metal applications and drivers in Linux to enable usage of these IPI based APIs. However, there may be cases where neither of these PM stacks are used in an end application due to various constraints like using a custom operating system without PM support, etc. In such cases, where runtime PM is not enabled but some level of power savings needs to be achieved, by powering down unused blocks within the SoC, there are techniques that can be applied. First a list of all blocks that are not used in the application is derived from the design. For example, blocks like GPU, USB may not be used but will remain ON consuming power. The solution is to turn-off these unused blocks in FSBL. Similarly, clocks can be gated for unused blocks. Here is an example flow on how this can be done:
Examine the power states of all islands
Examine active clocks
Examine Resets
List out Power Islands/ clocks/resets for blocks that are not used.
Put the blocks in reset
Gate Clocks
Power Down Domains
Inspect Clocks and Resets
Clock control registers are present in CRL_APB and CRF_APB and can be used to examine the current states of peripheral clocks. Some clocks are active by default at reset and so might be ungated and resulting in unnecessary power consumption. To get a list of all clocks that are active at reset can be found by examining the CLK_ACT bit in *_REF_CTRL registers in CRF_APB and CRL_APB registers. Refer to https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html
For example, DP_VIDEO clock is active at reset. So, it might be causing some unnecessary power drain even if the DP is not used and held in reset.
Here are the xsdb commands to inspect clocks and resets:
targets -set -filter {name =~ "PSU"}
# LPD clocks and Resets
rrd crl_apb
#FPD clocks and Resets
rrd crf_apb
Inspect Power Islands
Power Island states can be read back from PMU global registers. Here is the command to read out the power state register:
targets -set -filter {name =~ "PSU"}
# Read Power Status of Islands
rrd pmu_global pwr_state
# Example Output:
pwr_state: 00dffcbf
pl (Bits [23]): 1 fp (Bits [22]): 1 usb1 (Bits [21]): 0
usb0 (Bits [20]): 1 ocm_bank3 (Bits [19]): 1 ocm_bank2 (Bits [18]): 1
ocm_bank1 (Bits [17]): 1 ocm_bank0 (Bits [16]): 1 tcm1b (Bits [15]): 1
tcm1a (Bits [14]): 1 tcm0b (Bits [13]): 1 tcm0a (Bits [12]): 1
r5_1 (Bits [11]): 1 r5_0 (Bits [10]): 1 l2_bank0 (Bits [7]): 1
pp1 (Bits [5]): 1 pp0 (Bits [4]): 1 acpu3 (Bits [3]): 1
acpu2 (Bits [2]): 1 acpu1 (Bits [1]): 1 acpu0 (Bits [0]): 1
Adding Power and Clock controls in FSBL
For applications that don't use EEMI, the easy way to power down and clock gate unused blocks is by adding the control code into FSBL hooks. This technique will work for most of the use-cases.
The example code below can be customized to power down the unused blocks at FSBL post psu_init stage in xfsbl_hooks.c:
#define ZU_PMU_PWRDN_STATUS 0xFFD80210
#define ZU_PMU_PWRDN_INT_EN 0xFFD80218
#define ZU_PMU_PWRDN_TRIG 0xFFD80220
#define ZU_BIT(n) (1U << (n))
#define ZU_PWRDN_ACPU1_MASK ZU_BIT(1)
#define ZU_PWRDN_ACPU2_MASK ZU_BIT(2)
#define ZU_PWRDN_ACPU3_MASK ZU_BIT(3)
#define ZU_PWRDN_PP0_MASK ZU_BIT(4)
#define ZU_PWRDN_PP1_MASK ZU_BIT(5)
#define ZU_PWRDN_RPU_MASK ZU_BIT(10)
#define ZU_PWRDN_TCM0A_MASK ZU_BIT(12)
#define ZU_PWRDN_TCM0B_MASK ZU_BIT(13)
#define ZU_PWRDN_TCM1A_MASK ZU_BIT(14)
#define ZU_PWRDN_TCM1B_MASK ZU_BIT(15)
#define ZU_PWRDN_USB0_MASK ZU_BIT(20)
#define ZU_PWRDN_USB1_MASK ZU_BIT(21)
static void ZU_PowerDown(u32 IslandMask)
{
Xil_Out32(ZU_PMU_PWRDN_INT_EN, IslandMask);
Xil_Out32(ZU_PMU_PWRDN_TRIG, IslandMask);
/* Loop until all power down reqs are served */
while((Xil_In32(ZU_PMU_PWRDN_STATUS)) != 0);
}
/*** Add below code at the end of XFsbl_HookPsuInit */
ZU_PowerDown(ZU_PWRDN_ACPU1_MASK);
ZU_PowerDown(ZU_PWRDN_ACPU2_MASK);
ZU_PowerDown(ZU_PWRDN_ACPU3_MASK);
ZU_PowerDown(ZU_PWRDN_PP0_MASK);
ZU_PowerDown(ZU_PWRDN_PP1_MASK);
ZU_PowerDown(ZU_PWRDN_RPU_MASK);
ZU_PowerDown(ZU_PWRDN_TCM0A_MASK);
ZU_PowerDown(ZU_PWRDN_TCM0B_MASK);
ZU_PowerDown(ZU_PWRDN_TCM1A_MASK);
ZU_PowerDown(ZU_PWRDN_TCM1B_MASK);
ZU_PowerDown(ZU_PWRDN_USB0_MASK);
ZU_PowerDown(ZU_PWRDN_USB1_MASK);
© Copyright 2019 - 2022 Xilinx Inc. Privacy Policy