From dde36d829d2bbf0467bbe920af91b2df348e1c03 Mon Sep 17 00:00:00 2001 From: Sarat Chand Savitala Date: Tue, 24 Mar 2015 15:42:31 +0530 Subject: [PATCH] sw_apps:zynqmp_fsbl: Added ATF handoff params and PMU FW download support Provided support to pass handoff parameters to ATF which it will use to load further partitions. Provided support to load PMU firmware from FSBL. Signed-off-by: Sarat Chand Savitala --- lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c | 26 ++++ lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h | 24 +++- .../zynqmp_fsbl/src/xfsbl_image_header.c | 129 +++++++++++++++--- .../zynqmp_fsbl/src/xfsbl_image_header.h | 49 ++++++- .../zynqmp_fsbl/src/xfsbl_partition_load.c | 17 ++- 5 files changed, 218 insertions(+), 27 deletions(-) diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c index e8acc360..6ce28976 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c @@ -657,6 +657,9 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) u64 RunningCpuHandoffAddress=0U; u32 RunningCpuExecState=0U; s32 RunningCpuHandoffAddressPresent=FALSE; + u32 NoOfPartitions; + u32 PartitionIndex; + u32 PartitionAttributes; /** * if JTAG bootmode, be in while loop as of now @@ -714,6 +717,29 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) goto END; } + /* If PMU FW is present then handoff it to PMU MicroBlaze */ + NoOfPartitions = + FsblInstancePtr->ImageHeader.ImageHeaderTable.NoOfPartitions; + for (PartitionIndex = 0; + PartitionIndex < NoOfPartitions; PartitionIndex++) + { + PartitionAttributes = FsblInstancePtr->ImageHeader. + PartitionHeader[PartitionIndex].PartitionAttributes; + if ((PartitionAttributes & XIH_PH_ATTRB_DEST_DEVICE_MASK) + == XIH_PH_ATTRB_DEST_DEVICE_PMU) + { + /* Wakeup the processor */ + XFsbl_Out32(PMU_GLOBAL_GLOBAL_CNTRL, + XFsbl_In32(PMU_GLOBAL_GLOBAL_CNTRL) | 0x1); + + /* wait until done waking up */ + while((XFsbl_In32(PMU_GLOBAL_GLOBAL_CNTRL) & + PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK) == + PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK ) {;} + } + + } + /** * Flush the L1 data cache and L2 cache */ diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h index dacddf4f..b79bde85 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h @@ -277,6 +277,9 @@ extern "C" { */ #define PMU_GLOBAL_BASEADDR 0XFFD80000U +#define PMU_GLOBAL_GLOBAL_CNTRL ( ( PMU_GLOBAL_BASEADDR ) + 0X00000000U ) +#define PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK 0X00010000U + /* rpu */ /** @@ -371,6 +374,21 @@ extern "C" { */ #define RSA_CORE_CTRL ( ( RSA_CORE_BASEADDR ) + 0X00000010U ) +/* LPD_SLCR Base Address */ +#define LPD_SLCR_BASEADDR 0XFF410000U + +/* Register: LPD_SLCR_PERSISTENT4 */ +#define LPD_SLCR_PERSISTENT4 ( ( LPD_SLCR_BASEADDR ) + 0X00000030U ) + +/* Register: LPD_SLCR_PERSISTENT5 */ +#define LPD_SLCR_PERSISTENT5 ( ( LPD_SLCR_BASEADDR ) + 0X00000034U ) + +/* IPI Base Address */ +#define IPI_BASEADDR 0XFF300000U + +/* Register: IPI_PMU_0_TRIG */ +#define IPI_PMU_0_TRIG ( ( IPI_BASEADDR ) + 0X00030000U ) +#define IPI_APU_TRIG_PMU_0_SHIFT 16U /**************************** Type Definitions *******************************/ @@ -382,7 +400,11 @@ extern "C" { * For error reporting PMU_GLOBAL_PERS_GLOB_GEN_STORAGE1 is used */ #define XFSBL_ERROR_STATUS_REGISTER_OFFSET (PMU_GLOBAL_PERS_GLOB_GEN_STORAGE1) -#define XFSBL_PMU_RAM_ADDRESS (0xFFDC0000U) + + +/* PMU RAM address for PMU FW */ +#define XFSBL_PMU_RAM_START_ADDRESS (0xFFDC0000U) +#define XFSBL_PMU_RAM_END_ADDRESS (0xFFDDFFFFU) /** * ARM Processor defines diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.c index 507f12e7..16a063c9 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.c @@ -115,9 +115,12 @@ __inline u32 XFsbl_GetA53ExecState( /************************** Function Prototypes ******************************/ static u32 XFsbl_ValidateImageHeaderTable( XFsblPs_ImageHeaderTable * ImageHeaderTable); -static u32 XFsbl_CheckValidMemoryAddress(u64 Address, u32 CpuId); +static u32 XFsbl_CheckValidMemoryAddress(u64 Address, u32 CpuId, u32 DevId); +static void XFsbl_SetATFHandoffParameters( + XFsblPs_PartitionHeader *PartitionHeader, u32 EntryCount); /************************** Variable Definitions *****************************/ +XFsblPs_ATFHandoffParams ATFHandoffParams; /****************************************************************************/ /** @@ -289,6 +292,9 @@ u32 XFsbl_ReadImageHeader(XFsblPs_ImageHeader * ImageHeader, u32 ImageHeaderTableAddressOffset=0U; u32 PartitionHeaderAddress=0U; u32 PartitionIndex=0U; + XFsblPs_PartitionHeader *CurrPartitionHdr; + u32 EntryCount = 0; + u32 DestnCPU; /** * Read the Image Header Table offset from @@ -377,6 +383,33 @@ u32 XFsbl_ReadImageHeader(XFsblPs_ImageHeader * ImageHeader, } #endif + /** + * Assumption: Next partition corresponds to ATF + * The first partition of an application will have a non zero + * execution address. All the remaining partitions of that + * application will have 0 as execution address. Hence look for + * the non zero execution address for partition which is not + * the first one and ensure the CPU is A53 + */ + + CurrPartitionHdr = &ImageHeader->PartitionHeader[PartitionIndex]; + + DestnCPU = XFsbl_GetDestinationCpu(CurrPartitionHdr); + + if ((PartitionIndex > 1) && (EntryCount < XFSBL_MAX_ENTRIES_FOR_ATF) && + (CurrPartitionHdr->DestinationExecutionAddress != 0U) && + (((DestnCPU >= XIH_PH_ATTRB_DEST_CPU_A53_0) && + (DestnCPU <= XIH_PH_ATTRB_DEST_CPU_A53_3)))) + { + /** + * Populate handoff parameters to ATF + * These correspond to the partition of application + * which ATF will be loading + */ + XFsbl_SetATFHandoffParameters(CurrPartitionHdr, EntryCount); + EntryCount++; + } + /** * Update the next partition present address */ @@ -385,15 +418,33 @@ u32 XFsbl_ReadImageHeader(XFsblPs_ImageHeader * ImageHeader, * XIH_PARTITION_WORD_LENGTH; } + /** + * After setting handoff parameters of all partitions to ATF, + * Store lower address of the structure at Persistent register 4 + * and higher address at Persistent register 5 + */ + XFsbl_Out32(LPD_SLCR_PERSISTENT4,(u32)(((PTRSIZE)(&ATFHandoffParams)) & 0xFFFFFFFF)); + XFsbl_Out32(LPD_SLCR_PERSISTENT5, (u32)(((PTRSIZE)(&ATFHandoffParams)) >> 32)); + END: return Status; } -static u32 XFsbl_CheckValidMemoryAddress(u64 Address, u32 CpuId) +static u32 XFsbl_CheckValidMemoryAddress(u64 Address, u32 CpuId, u32 DevId) { u32 Status = XFSBL_SUCCESS; + /* Check if Address is in the range of PMU RAM for PMU FW */ + if (DevId == XIH_PH_ATTRB_DEST_DEVICE_PMU) + { + if ((Address >= XFSBL_PMU_RAM_START_ADDRESS) && + (Address < XFSBL_PMU_RAM_END_ADDRESS) ) + { + goto END; + } + } + /** * Check if Address is in the range of TCM for R5 */ @@ -471,7 +522,7 @@ u32 XFsbl_ValidatePartitionHeader( { u32 Status = XFSBL_SUCCESS; u32 DestinationCpu=0U; - /* u32 RpuGlobalCntl=0; */ + u32 DestinationDevice=0; s32 IsEncrypted=FALSE, IsAuthenticated=FALSE; @@ -492,7 +543,7 @@ u32 XFsbl_ValidatePartitionHeader( DestinationCpu = XFsbl_GetDestinationCpu(PartitionHeader); - + DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); /** * Partition fields Validation */ @@ -604,7 +655,7 @@ u32 XFsbl_ValidatePartitionHeader( */ Status = XFsbl_CheckValidMemoryAddress( PartitionHeader->DestinationLoadAddress, - DestinationCpu); + DestinationCpu, DestinationDevice); if (Status != XFSBL_SUCCESS) { goto END; @@ -693,23 +744,6 @@ u32 XFsbl_ValidatePartitionHeader( goto END; } - /** - * Check for PMU address not in PMU RAM - */ - if (XFsbl_GetDestinationDevice(PartitionHeader) == - XIH_PH_ATTRB_DEST_DEVICE_PMU) - { - if (PartitionHeader->DestinationLoadAddress != - XFSBL_PMU_RAM_ADDRESS) - { - Status = XFSBL_ERROR_INVALID_LOAD_ADDRESS; - XFsbl_Printf(DEBUG_GENERAL, - "XFSBL_ERROR_INVALID_LOAD_ADDRESS\n\r"); - goto END; - } - } - - /** * Print Partition Header Details */ @@ -731,3 +765,54 @@ u32 XFsbl_ValidatePartitionHeader( END: return Status; } + +/****************************************************************************/ +/** +* This function sets the handoff parameters to the ARM Trusted Firmware (ATF) +* Some of the inputs for this are taken from FSBL partition header +* A pointer to the structure containing these parameters is stored in +* persistent register 5, which ATF reads +* +* @param PartitionHeader is pointer to the XFsblPs_PartitionHeader structure +* +* @return None +* +* @note +* +*****************************************************************************/ +static void XFsbl_SetATFHandoffParameters( + XFsblPs_PartitionHeader *PartitionHeader, u32 EntryCount) +{ + u32 PartitionAttributes; + u64 PartitionFlags; + + PartitionAttributes = PartitionHeader->PartitionAttributes; + + PartitionFlags = + (((PartitionAttributes & XIH_PH_ATTRB_A53_EXEC_ST_MASK) + >> XIH_ATTRB_A53_EXEC_ST_SHIFT_DIFF) | + ((PartitionAttributes & XIH_PH_ATTRB_ENDIAN_MASK) + >> XIH_ATTRB_ENDIAN_SHIFT_DIFF) | + ((PartitionAttributes & XIH_PH_ATTRB_TR_SECURE_MASK) + << XIH_ATTRB_TR_SECURE_SHIFT_DIFF) | + ((PartitionAttributes & XIH_PH_ATTRB_TARGET_EL_MASK) + << XIH_ATTRB_TARGET_EL_SHIFT_DIFF) | + ((PartitionAttributes & XIH_PH_ATTRB_DEST_CPU_A53_MASK) + >> XIH_ATTRB_DEST_CPU_A53_SHIFT_DIFF)); + + /* Insert magic string */ + if (EntryCount == 0) + { + ATFHandoffParams.MagicValue[0] = 'X'; + ATFHandoffParams.MagicValue[1] = 'L'; + ATFHandoffParams.MagicValue[2] = 'N'; + ATFHandoffParams.MagicValue[3] = 'X'; + } + + ATFHandoffParams.NumEntries = EntryCount + 1; + + ATFHandoffParams.Entry[EntryCount].EntryPoint = + PartitionHeader->DestinationExecutionAddress; + ATFHandoffParams.Entry[EntryCount].PartitionFlags = PartitionFlags; + +} diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.h index d263eff0..5b52f5a0 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_image_header.h @@ -71,6 +71,7 @@ extern "C" { * Boot header field offset */ #define XIH_BH_IH_OFFSET (0x3CU) +#define XIH_BH_TOTAL_PFW_LENGTH_OFFSET (0x38U) #define XIH_BH_IMAGE_ATTRB_OFFSET (0x44U) #define XIH_BH_IH_TABLE_OFFSET (0x98U) #define XIH_BH_PH_TABLE_OFFSET (0x9CU) @@ -82,6 +83,7 @@ extern "C" { * Defines for length of the headers */ #define XIH_FIELD_LEN (4U) +#define XIH_PFW_LEN_FIELD_LEN (4U) #define XIH_IHT_LEN (64U) #define XIH_PH_LEN (64U) @@ -127,6 +129,7 @@ extern "C" { /** * Partition Attribute fields */ +#define XIH_PH_ATTRB_ENDIAN_MASK (0x40000U) #define XIH_PH_ATTRB_PART_OWNER_MASK (0x30000U) #define XIH_PH_ATTRB_RSA_SIGNATURE_MASK (0x8000U) #define XIH_PH_ATTRB_CHECKSUM_MASK (0x7000U) @@ -134,7 +137,9 @@ extern "C" { #define XIH_PH_ATTRB_ENCRYPTION_MASK (0x0080U) #define XIH_PH_ATTRB_DEST_DEVICE_MASK (0x0070U) #define XIH_PH_ATTRB_A53_EXEC_ST_MASK (0x0008U) - +#define XIH_PH_ATTRB_TARGET_EL_MASK (0x0006U) +#define XIH_PH_ATTRB_TR_SECURE_MASK (0x0001U) +#define XIH_PH_ATTRB_DEST_CPU_A53_MASK (0x0600U) /** * Partition Attribute Values @@ -164,6 +169,30 @@ extern "C" { #define XIH_PH_ATTRB_A53_EXEC_ST_AA32 (0x0008U) #define XIH_PH_ATTRB_A53_EXEC_ST_AA64 (0x0000U) +/** + * Below is the bit mapping of fields in the ATF Handoff parameters + * with that of Partition header. The number of bits shifted is + * is based on the difference between these two offsets + * + * ATFHandoffParams PartitionHeader Shift + * Parameter PartitionFlags PartitionAttributes difference + * ---------------------------------------------------------------------- + * Exec State 0 3 3 right + * ENDIAN 1 18 17 right + * SECURE 2 0 2 left + * EL 3:4 1:2 2 left + * CPU_A53 5:6 9:10 4 right + */ +#define XIH_ATTRB_A53_EXEC_ST_SHIFT_DIFF (3U) +#define XIH_ATTRB_ENDIAN_SHIFT_DIFF (17U) +#define XIH_ATTRB_TR_SECURE_SHIFT_DIFF (2U) +#define XIH_ATTRB_TARGET_EL_SHIFT_DIFF (2U) +#define XIH_ATTRB_DEST_CPU_A53_SHIFT_DIFF (4U) + + +/* Number of entries possible in ATF: 4 cores * 2 (secure, nonsecure) */ +#define XFSBL_MAX_ENTRIES_FOR_ATF 8 + /**************************** Type Definitions *******************************/ /** @@ -218,6 +247,24 @@ typedef struct { /**< Partition header */ } XFsblPs_ImageHeader; +/* Structure corresponding to each partition entry */ +typedef struct { + u64 EntryPoint; + /**< Entry point */ + u64 PartitionFlags; + /**< Attributes of partition */ +} XFsblPs_PartitionEntry; + +/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */ +typedef struct { + char8 MagicValue[4]; + /**< 32 bit magic string */ + u32 NumEntries; + /**< Number of Entries */ + XFsblPs_PartitionEntry Entry[XFSBL_MAX_ENTRIES_FOR_ATF]; + /**< Structure corresponding to each entry */ +} XFsblPs_ATFHandoffParams; + /***************** Macros (Inline Functions) Definitions *********************/ __inline u32 XFsbl_GetPartitionOwner( XFsblPs_PartitionHeader * PartitionHeader); diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_partition_load.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_partition_load.c index f90715bd..e866c688 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_partition_load.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_partition_load.c @@ -737,9 +737,6 @@ static u32 XFsbl_PartitionCopy(XFsblPs * FsblInstancePtr, u32 PartitionNum) * Copy the PL to temporary DDR Address * Copy the PS to Load Address * Copy the PMU firmware to PMU RAM - * (It may be good if we copy to DDR instead of PMU RAM - * And finish the PMU RAM copy at handoff so that PMU is - * not in waiting state - Need to check the exact working of PMU) */ DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); LoadAddress = PartitionHeader->DestinationLoadAddress; @@ -834,6 +831,20 @@ static u32 XFsbl_PartitionCopy(XFsblPs * FsblInstancePtr, u32 PartitionNum) } #endif + if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PMU) + { + /* Trigger PMU0 IPI in PMU IPI TRIG Reg */ + XFsbl_Out32(IPI_PMU_0_TRIG, IPI_APU_TRIG_PMU_0_SHIFT); + + /** + * Wait until PMU Microblaze goes to sleep state, + * before starting firmware download to PMU RAM + */ + while((XFsbl_In32(PMU_GLOBAL_GLOBAL_CNTRL) & + PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK) != + PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK ) {;} + } + /** * Copy the partition to PS_DDR/PL_DDR/TCM */