diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_config.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_config.h index 5ce02123..632df53d 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_config.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_config.h @@ -120,8 +120,9 @@ extern "C" { * - FSBL_SD_EXCLUDE SD code will be excluded * - FSBL_RSA_EXCLUDE RSA (authentication) code will be excluded * - FSBL_AES_EXCLUDE AES (decryption) code will be excluded - * - FSBL_BS_EXCLUDE AES (PL bitstream) code will be excluded + * - FSBL_BS_EXCLUDE PL bitstream code will be excluded * - FSBL_SHA2_EXCLUDE SHA2 code will be excluded + * - FSBL_EARLY_HANDOFF_EXCLUDE Early handoff related code will be excluded */ #define FSBL_NAND_EXCLUDE_VAL (0U) #define FSBL_QSPI_EXCLUDE_VAL (0U) @@ -130,6 +131,7 @@ extern "C" { #define FSBL_AES_EXCLUDE_VAL (0U) #define FSBL_BS_EXCLUDE_VAL (0U) #define FSBL_SHA2_EXCLUDE_VAL (1U) +#define FSBL_EARLY_HANDOFF_EXCLUDE_VAL (0U) #if FSBL_NAND_EXCLUDE_VAL #define FSBL_NAND_EXCLUDE @@ -159,6 +161,11 @@ extern "C" { #define FSBL_SHA2_EXCLUDE #endif +#if FSBL_EARLY_HANDOFF_EXCLUDE_VAL +#define FSBL_EARLY_HANDOFF_EXCLUDE +#endif + + /************************** Function Prototypes ******************************/ diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_error.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_error.h index 97514bc4..232899c2 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_error.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_error.h @@ -95,6 +95,8 @@ extern "C" { #define XFSBL_SUCCESS (0x0U) #define XFSBL_STATUS_JTAG (0x1U) #define XFSBL_SUCCESS_NOT_PARTITION_OWNER (0x2U) +#define XFSBL_STATUS_CONTINUE_PARTITION_LOAD (0x3U) +#define XFSBL_STATUS_CONTINUE_OTHER_HANDOFF (0x4U) #define XFSBL_ERROR_UNSUPPORTED_BOOT_MODE (0x6U) #define XFSBL_WDT_INIT_FAILED (0x7U) diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c index 8797c884..0a43cc49 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_handoff.c @@ -712,13 +712,17 @@ static void XFsbl_CopyIVT(u32 CpuSettings) * * @param FsblInstancePtr is pointer to the XFsbl Instance * + * @param PartitionNum is the partition number of the image + * + * @param EarlyHandoff is flag to indicate if called for early handoff or not + * * @return returns the error codes described in xfsbl_error.h on any error * * @note This function should not return incase of success * *****************************************************************************/ -u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) +u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr, u32 PartitionNum, u32 EarlyHandoff) { u32 Status=XFSBL_SUCCESS; u32 CpuIndex=0U; @@ -729,9 +733,9 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) u64 RunningCpuHandoffAddress=0U; u32 RunningCpuExecState=0U; s32 RunningCpuHandoffAddressPresent=FALSE; - u32 NoOfPartitions; - u32 PartitionIndex; - u32 PartitionAttributes; + u32 CpuNeedsEarlyHandoff = FALSE; + + static u32 CpuIndexEarlyHandoff = 0; /** * if JTAG bootmode, be in while loop as of now @@ -775,7 +779,7 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) /** * FSBL hook before Handoff */ - Status = XFsbl_HookBeforeHandoff(); + Status = XFsbl_HookBeforeHandoff(EarlyHandoff); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_HOOK_BEFORE_HANDOFF; @@ -818,100 +822,150 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) * get cpu out of reset * */ - CpuIndex=0U; + + /** + * If we are doing early handoff, remember the CPU index to avoid + * traversing through for the next early handoff + */ + if (EarlyHandoff == TRUE) { + CpuIndex = CpuIndexEarlyHandoff; + } + while (CpuIndex < FsblInstancePtr->HandoffCpuNo) { CpuSettings = - FsblInstancePtr->HandoffValues[CpuIndex].CpuSettings; + FsblInstancePtr->HandoffValues[CpuIndex].CpuSettings; CpuId = CpuSettings & XIH_PH_ATTRB_DEST_CPU_MASK; ExecState = CpuSettings & XIH_PH_ATTRB_A53_EXEC_ST_MASK; /** - * Check if handoff address is present + * Run the code in this loop in the below conditions: + * - This function called for early handoff and CPU needs early handoff + * - This function called for regular handoff and CPU doesn't need early + * handoff + * - This function called for regular handoff and CPU needs early + * handoff AND if handoff is to running CPU + * */ - if (CpuId != FsblInstancePtr->ProcessorID) - { + CpuNeedsEarlyHandoff = XFsbl_CheckEarlyHandoffCpu(CpuId); + if (((EarlyHandoff == TRUE) && (CpuNeedsEarlyHandoff == TRUE)) || + ((EarlyHandoff != TRUE) && (CpuNeedsEarlyHandoff != TRUE)) || + (((EarlyHandoff != TRUE) && (CpuNeedsEarlyHandoff == TRUE)) && + (CpuId == FsblInstancePtr->ProcessorID))) { + /** - * Check for power status of the cpu - * Update the IVT - * Take cpu out of reset + * Check if handoff address is present */ - Status = XFsbl_SetCpuPwrSettings( - CpuSettings, XFSBL_CPU_POWER_UP); - if (XFSBL_SUCCESS != Status) + if (CpuId != FsblInstancePtr->ProcessorID) { - XFsbl_Printf(DEBUG_GENERAL,"Power Up " - "Cpu 0x%0lx failed \n\r", CpuId); - - XFsbl_Printf(DEBUG_GENERAL, - "XFSBL_ERROR_PWR_UP_CPU\n\r"); - Status = XFSBL_ERROR_PWR_UP_CPU; - goto END; - } - - /** - * Read the handoff address from structure - */ - HandoffAddress = (u64 ) - FsblInstancePtr->HandoffValues[CpuIndex].HandoffAddress; - - /** - * Update the handoff address at reset vector address - */ - XFsbl_UpdateResetVector(HandoffAddress, CpuSettings); - - XFsbl_Printf(DEBUG_INFO,"CPU 0x%0lx reset release, " - "Exec State 0x%0lx, HandoffAddress: %0lx\n\r", - CpuId, ExecState, (PTRSIZE )HandoffAddress); - - /** - * Reset the flag at 0xffffff80 - * Write Zero at 0xffffff80 - */ - XFsbl_Out32(XFSBL_HANDOFF_FLAG_ADDR, 0U); - /** - * Take CPU out of reset - */ - Status = XFsbl_SetCpuPwrSettings( - CpuSettings, XFSBL_CPU_SWRST); - if (XFSBL_SUCCESS != Status) - { - goto END; - } - - /** - * Wait till the CPU executed the - * predefined code for R5 - */ - if ((CpuId == XIH_PH_ATTRB_DEST_CPU_R5_0) || - (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_1) || - (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_L) ) - { - while (XFsbl_In32(XFSBL_HANDOFF_FLAG_ADDR) - != 0xAAU) + /** + * Check for power status of the cpu + * Update the IVT + * Take cpu out of reset + */ + Status = XFsbl_SetCpuPwrSettings( + CpuSettings, XFSBL_CPU_POWER_UP); + if (XFSBL_SUCCESS != Status) { - /** - * wait for flag - * block for MISRA C compliance - */ - }; - } + XFsbl_Printf(DEBUG_GENERAL,"Power Up " + "Cpu 0x%0lx failed \n\r", CpuId); - } else { - /** - * Update the running cpu handoff address - */ - RunningCpuHandoffAddressPresent = TRUE; - RunningCpuHandoffAddress = (u64 ) - FsblInstancePtr->HandoffValues[CpuIndex].HandoffAddress; - RunningCpuExecState = ExecState; + XFsbl_Printf(DEBUG_GENERAL, + "XFSBL_ERROR_PWR_UP_CPU\n\r"); + Status = XFSBL_ERROR_PWR_UP_CPU; + goto END; + } + + /** + * Read the handoff address from structure + */ + HandoffAddress = (u64 ) + FsblInstancePtr->HandoffValues[CpuIndex].HandoffAddress; + + /** + * Update the handoff address at reset vector address + */ + XFsbl_UpdateResetVector(HandoffAddress, CpuSettings); + + XFsbl_Printf(DEBUG_INFO,"CPU 0x%0lx reset release, " + "Exec State 0x%0lx, HandoffAddress: %0lx\n\r", + CpuId, ExecState, (PTRSIZE )HandoffAddress); + + /** + * Reset the flag at 0xffffff80 + * Write Zero at 0xffffff80 + */ + XFsbl_Out32(XFSBL_HANDOFF_FLAG_ADDR, 0U); + /** + * Take CPU out of reset + */ + Status = XFsbl_SetCpuPwrSettings( + CpuSettings, XFSBL_CPU_SWRST); + if (XFSBL_SUCCESS != Status) + { + goto END; + } + + /** + * Wait till the CPU executed the + * predefined code for R5 + */ + if ((CpuId == XIH_PH_ATTRB_DEST_CPU_R5_0) || + (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_1) || + (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_L) ) + { + while (XFsbl_In32(XFSBL_HANDOFF_FLAG_ADDR) + != 0xAAU) + { + /** + * wait for flag + * block for MISRA C compliance + */ + }; + } + + } else { + /** + * Update the running cpu handoff address + */ + RunningCpuHandoffAddressPresent = TRUE; + RunningCpuHandoffAddress = (u64 ) + FsblInstancePtr->HandoffValues[CpuIndex].HandoffAddress; + RunningCpuExecState = ExecState; + } + } + + if ((EarlyHandoff == TRUE) && (CpuNeedsEarlyHandoff == TRUE)){ + + /* Enable cache again as we will continue loading partitions */ + Xil_DCacheEnable(); + + if (PartitionNum < + (FsblInstancePtr-> + ImageHeader.ImageHeaderTable.NoOfPartitions-1U)) { + /** + * If this is not the last handoff CPU, return back and continue + * loading remaining partitions in stage 3 + */ + CpuIndexEarlyHandoff++; + Status = XFSBL_STATUS_CONTINUE_PARTITION_LOAD; + } + else { + /** + * Early handoff to all required CPUs is done, continue with + * regular handoff for remaining applications, as applicable + */ + Status = XFSBL_STATUS_CONTINUE_OTHER_HANDOFF; + } + goto END; } /** * Go to the next cpu */ CpuIndex++; + CpuIndexEarlyHandoff++; } @@ -955,3 +1009,93 @@ u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr) END: return Status; } + +/*****************************************************************************/ +/** + * This function determines if the given CPU needs early handoff or not. + * Currently early handoff is provided for R5 + * + * @param CpuId is Mask of CPU Id in partition attributes + * + * @return TRUE if this CPU needs early handoff, and FALSE if not + * + *****************************************************************************/ +u32 XFsbl_CheckEarlyHandoffCpu(u32 CpuId) +{ + u32 CpuNeedEarlyHandoff = FALSE; + + if ((CpuId == XIH_PH_ATTRB_DEST_CPU_R5_0) || + (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_1) || + (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_L)) + { + CpuNeedEarlyHandoff = TRUE; + } + + return CpuNeedEarlyHandoff; + +} + +/*****************************************************************************/ +/** + * This function determines if the given partition needs early handoff + * + * @param FsblInstancePtr is pointer to the XFsbl Instance + * + * @param PartitionNum is the partition number of the image + * + * @return TRUE if this partitions needs early handoff, and FALSE if not + * + *****************************************************************************/ +u32 XFsbl_CheckEarlyHandoff(XFsblPs * FsblInstancePtr, u32 PartitionNum) +{ + + u32 Status = FALSE; +#if defined(XFSBL_EARLY_HANDOFF) + u32 CpuNeedsEarlyHandoff = FALSE; + u32 DestinationCpu = 0; + u32 DestinationDev = 0; + u32 DestinationCpuNxt = 0; + u32 DestinationDevNxt = 0; + + DestinationCpu = XFsbl_GetDestinationCpu( + &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]); + DestinationDev = XFsbl_GetDestinationDevice( + &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]); + if ((DestinationCpu == XIH_PH_ATTRB_DEST_CPU_NONE) && + ((DestinationDev == XIH_PH_ATTRB_DEST_DEVICE_PS) || + (DestinationDev == XIH_PH_ATTRB_DEST_DEVICE_NONE))) + { + /* If dest device is not PS, retain the dest CPU as NONE/0 */ + DestinationCpu = FsblInstancePtr->ProcessorID; + } + + if ((PartitionNum + 1) <= + (FsblInstancePtr->ImageHeader.ImageHeaderTable.NoOfPartitions-1U)) { + + DestinationCpuNxt = XFsbl_GetDestinationCpu( + &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum + 1]); + DestinationDevNxt = XFsbl_GetDestinationDevice( + &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum + 1]); + + if ((DestinationCpuNxt == XIH_PH_ATTRB_DEST_CPU_NONE) && + ((DestinationDevNxt == XIH_PH_ATTRB_DEST_DEVICE_PS) || + (DestinationDevNxt == XIH_PH_ATTRB_DEST_DEVICE_NONE))) { + DestinationCpuNxt = FsblInstancePtr->ProcessorID; + } + } + + /** + * Early handoff needed if destination CPU needs early handoff AND + * if handoff CPU is not same as running CPU AND + * if this is the last partition of this application + */ + CpuNeedsEarlyHandoff = XFsbl_CheckEarlyHandoffCpu(DestinationCpu); + if ((CpuNeedsEarlyHandoff == TRUE) && + (DestinationCpu != FsblInstancePtr->ProcessorID) && + (DestinationCpuNxt != DestinationCpu)) { + + Status = TRUE; + } +#endif + return Status; +} diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.c index 0ea363f5..5762a799 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.c @@ -87,7 +87,7 @@ u32 XFsbl_HookAfterBSDownload(void ) } #endif -u32 XFsbl_HookBeforeHandoff(void ) +u32 XFsbl_HookBeforeHandoff(u32 EarlyHandoff) { u32 Status = XFSBL_SUCCESS; diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.h index 22615b75..39f3d799 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hooks.h @@ -74,7 +74,7 @@ u32 XFsbl_HookBeforeBSDownload(void ); u32 XFsbl_HookAfterBSDownload(void ); -u32 XFsbl_HookBeforeHandoff(void ); +u32 XFsbl_HookBeforeHandoff(u32 EarlyHandoff); #ifdef __cplusplus diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h index 971a2d1d..0f83e154 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_hw.h @@ -303,6 +303,7 @@ extern "C" { #define PMU_GLOBAL_GLOBAL_CNTRL ( ( PMU_GLOBAL_BASEADDR ) + 0X00000000U ) #define PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK 0X00010000U +#define PMU_GLOBAL_GLOBAL_CNTRL_FW_IS_PRESENT_MASK 0X00000010U /* Register: PMU_GLOBAL_REQ_PWRUP_INT_EN */ #define PMU_GLOBAL_REQ_PWRUP_INT_EN ( ( PMU_GLOBAL_BASEADDR ) + 0X00000118U ) @@ -549,6 +550,14 @@ extern "C" { #define XFSBL_BS #endif + +/** + * Definition for early handoff feature to be included + */ +#if !defined(FSBL_EARLY_HANDOFF_EXCLUDE) +#define XFSBL_EARLY_HANDOFF +#endif + /** * Definition for SHA2 to be included */ diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.c b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.c index 6a5070d9..dba514e1 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.c +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.c @@ -81,6 +81,7 @@ int main(void ) u32 FsblStatus = XFSBL_SUCCESS; u32 FsblStage = XFSBL_STAGE1; u32 PartitionNum=0U; + u32 EarlyHandoff = FALSE; /** * Initialize globals. @@ -185,20 +186,30 @@ int main(void ) /** * Check loading all partitions is completed */ + + FsblStatus = XFsbl_CheckEarlyHandoff(&FsblInstancePtr, PartitionNum); + if (PartitionNum < (FsblInstancePtr.ImageHeader.ImageHeaderTable.NoOfPartitions-1U)) { - /** - * No need to change the Fsbl Stage - * Load the next partition - */ - PartitionNum++; + if (TRUE == FsblStatus) { + EarlyHandoff = TRUE; + FsblStage = XFSBL_STAGE4; + } + else { + /** + * No need to change the Fsbl Stage + * Load the next partition + */ + PartitionNum++; + } } else { /** * No more partitions present, go to handoff stage */ XFsbl_Printf(DEBUG_INFO,"All Partitions Loaded \n\r"); FsblStage = XFSBL_STAGE4; + EarlyHandoff = FsblStatus; } } /* End of else loop for Load Success */ @@ -216,9 +227,21 @@ int main(void ) * xip * ps7 post config */ - FsblStatus = XFsbl_Handoff(&FsblInstancePtr); - if (XFSBL_SUCCESS != FsblStatus) - { + FsblStatus = XFsbl_Handoff(&FsblInstancePtr, PartitionNum, EarlyHandoff); + + if (XFSBL_STATUS_CONTINUE_PARTITION_LOAD == FsblStatus) { + XFsbl_Printf(DEBUG_INFO,"Early handoff to a application complete \n\r"); + XFsbl_Printf(DEBUG_INFO,"Continuing to load remaining partitions \n\r"); + + PartitionNum++; + FsblStage = XFSBL_STAGE3; + } + else if (XFSBL_STATUS_CONTINUE_OTHER_HANDOFF == FsblStatus) { + XFsbl_Printf(DEBUG_INFO,"Early handoff to a application complete \n\r"); + XFsbl_Printf(DEBUG_INFO,"Continuing handoff to other applications, if present \n\r"); + EarlyHandoff = FALSE; + } + else if (XFSBL_SUCCESS != FsblStatus) { /** * Error */ diff --git a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.h b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.h index c607439c..82f0fada 100644 --- a/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.h +++ b/lib/sw_apps/zynqmp_fsbl/src/xfsbl_main.h @@ -156,8 +156,10 @@ u32 XFsbl_PartitionLoad(XFsblPs * FsblInstancePtr, u32 PartitionNum); /** * Functions defined in xfsbl_handoff.c */ -u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr); +u32 XFsbl_Handoff (XFsblPs * FsblInstancePtr, u32 PartitionNum, u32 EarlyHandoff); void XFsbl_HandoffExit(u64 HandoffAddress, u32 Flags); +u32 XFsbl_CheckEarlyHandoffCpu(u32 CpuId); +u32 XFsbl_CheckEarlyHandoff(XFsblPs * FsblInstancePtr, u32 PartitionNum); /************************** Variable Definitions *****************************/