/** * * This function checks the power state of one or more power islands and * powers them up if required. * * @param Mask of Island(s) that need to be powered up * * @return XFSBL_SUCCESS for successful power up or * XFSBL_FAILURE otherwise. * * @note None. * ****************************************************************************/ u32 XFsbl_PowerUpIsland(u32 PwrIslandMask) { u32 RegVal; u32 Status = XFSBL_SUCCESS; /* Skip power-up request for QEMU */ if (XGet_Zynq_UltraMp_Platform_info() != (u32)XPLAT_ZYNQ_ULTRA_MPQEMU) { /* There is a single island for both R5_0 and R5_1 */ if ((PwrIslandMask & PMU_GLOBAL_PWR_STATE_R5_1_MASK) == PMU_GLOBAL_PWR_STATE_R5_1_MASK) { PwrIslandMask &= ~(PMU_GLOBAL_PWR_STATE_R5_1_MASK); PwrIslandMask |= PMU_GLOBAL_PWR_STATE_R5_0_MASK; } /* Power up request enable */ XFsbl_Out32(PMU_GLOBAL_REQ_PWRUP_INT_EN, PwrIslandMask); /* Trigger power up request */ XFsbl_Out32(PMU_GLOBAL_REQ_PWRUP_TRIG, PwrIslandMask); /* Poll for Power up complete */ do { RegVal = XFsbl_In32(PMU_GLOBAL_REQ_PWRUP_STATUS) & PwrIslandMask; } while (RegVal != 0x0U); } return Status; }
/** * This function is used to provide Reset to USB Phy on ZCU102 board. * * @param none * * @return none * *****************************************************************************/ void XFsbl_UsbPhyReset(void) { /* USB PHY Reset */ XFsbl_Out32(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOTMODE_1_HI); (void)usleep(DELAY_1_US); XFsbl_Out32(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOTMODE_1_LO); (void)usleep(DELAY_5_US); XFsbl_Out32(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOTMODE_1_HI); }
/** This is the function to write data to PCAP interface * * @param WrSize: Number of 32bit words that the DMA should write to * the PCAP interface * @param WrAddr: Linear memory space from where CSUDMA will read * the data to be written to PCAP interface * * @return None * *****************************************************************************/ u32 XFsbl_WriteToPcap(u32 WrSize, u8 *WrAddr) { u32 RegVal; u32 Status = XFSBL_SUCCESS; /* * Setup the SSS, setup the PCAP to receive from DMA source */ RegVal = XFsbl_In32(CSU_CSU_SSS_CFG) & CSU_CSU_SSS_CFG_PCAP_SSS_MASK; RegVal = RegVal | (XFSBL_CSU_SSS_SRC_SRC_DMA << CSU_CSU_SSS_CFG_PCAP_SSS_SHIFT); XFsbl_Out32(CSU_CSU_SSS_CFG, RegVal); /* Setup the source DMA channel */ XCsuDma_Transfer(&CsuDma, XCSUDMA_SRC_CHANNEL, (PTRSIZE) WrAddr, WrSize, 0); /* wait for the SRC_DMA to complete and the pcap to be IDLE */ XCsuDma_WaitForDone(&CsuDma, XCSUDMA_SRC_CHANNEL); /* Acknowledge the transfer has completed */ XCsuDma_IntrClear(&CsuDma, XCSUDMA_SRC_CHANNEL, XCSUDMA_IXR_DONE_MASK); XFsbl_Printf(DEBUG_GENERAL, "DMA transfer done \r\n"); Status = XFsbl_PcapWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } END: return Status; }
/****************************************************************************** * * This function is used to stop Watchdog * * @param None * * @return None * * @note None * *******************************************************************************/ void XFsbl_StopWdt(void) { u32 RegValue; XWdtPs_Stop(&Watchdog); /* Disable LPD System Watchdog Timer Error */ RegValue = XFsbl_In32(PMU_GLOBAL_ERROR_EN_1); RegValue &= ~(PMU_GLOBAL_ERROR_EN_1_LPD_SWDT_MASK); XFsbl_Out32(PMU_GLOBAL_ERROR_EN_1, RegValue); /* Disable generation of system reset by PMU due to LPD SWDT */ RegValue = XFsbl_In32(PMU_GLOBAL_ERROR_SRST_DIS_1); RegValue |= PMU_GLOBAL_ERROR_SRST_DIS_1_LPD_SWDT_MASK; XFsbl_Out32(PMU_GLOBAL_ERROR_SRST_DIS_1, RegValue); }
/** This function does the necessary initialization of PCAP interface * * @param None * * @return error status based on implemented functionality (SUCCESS by default) * *****************************************************************************/ u32 XFsbl_PcapInit(void) { u32 RegVal; u32 Status = XFSBL_SUCCESS; /* Take PCAP out of Reset */ RegVal = XFsbl_In32(CSU_PCAP_RESET); RegVal &= (~CSU_PCAP_RESET_RESET_MASK); XFsbl_Out32(CSU_PCAP_RESET, RegVal); /* Select PCAP mode and change PCAP to write mode */ RegVal = CSU_PCAP_CTRL_PCAP_PR_MASK; XFsbl_Out32(CSU_PCAP_CTRL, RegVal); XFsbl_Out32(CSU_PCAP_RDWR, 0x0); Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_PL_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_PL_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_PL_POWER_UP\r\n"); goto END; } /* Reset PL */ XFsbl_Out32(CSU_PCAP_PROG, 0x0U); usleep(PL_RESET_PERIOD_IN_US); XFsbl_Out32(CSU_PCAP_PROG, CSU_PCAP_PROG_PCFG_PROG_B_MASK); /* * Wait for PL_init completion * Bypass this check in platforms not supporting PCAP interface */ if ((XFSBL_PLATFORM != XFSBL_PLATFORM_REMUS) && (XFSBL_PLATFORM != XFSBL_PLATFORM_QEMU)) { RegVal = 0U; do { RegVal = XFsbl_In32(CSU_PCAP_STATUS) & CSU_PCAP_STATUS_PL_INIT_MASK; } while (RegVal != CSU_PCAP_STATUS_PL_INIT_MASK); } else { XFsbl_Printf(DEBUG_GENERAL, "PCAP interface is not supported in this platform \r\n"); } END: return Status; }
/** * This function is used to provide PCIe reset on ZCU102 board. * * @param none * * @return none * *****************************************************************************/ void XFsbl_PcieReset(void) { u32 RegVal = 0; u32 ICMCfg0; u32 ICMCfg1; ICMCfg0 = XFsbl_In32(SERDES_ICM_CFG0) & (SERDES_ICM_CFG0_L0_ICM_CFG_MASK | SERDES_ICM_CFG0_L1_ICM_CFG_MASK); ICMCfg1 = XFsbl_In32(SERDES_ICM_CFG1) & (SERDES_ICM_CFG1_L2_ICM_CFG_MASK | SERDES_ICM_CFG1_L3_ICM_CFG_MASK); /* Give reset only if we have PCIe in design */ if ((ICMCfg0 == ICM_CFG0_PCIE_PCIE) || (ICMCfg1 == ICM_CFG1_PCIE_PCIE)) { /* Set MIO31 direction as output */ XFsbl_Out32(GPIO_DIRM_1, GPIO_MIO31_MASK); /* Set MIO31 output enable */ XFsbl_Out32(GPIO_OEN_1, GPIO_MIO31_MASK); /* Set MIO31 to HIGH */ RegVal = XFsbl_In32(GPIO_DATA_1) | GPIO_MIO31_MASK; XFsbl_Out32(GPIO_DATA_1, RegVal); (void)usleep(DELAY_1_US); /* Set MIO31 to LOW */ RegVal = XFsbl_In32(GPIO_DATA_1) & ~(GPIO_MIO31_MASK); XFsbl_Out32(GPIO_DATA_1, RegVal); (void)usleep(DELAY_5_US); /* Set MIO31 to HIGH */ RegVal = XFsbl_In32(GPIO_DATA_1) | GPIO_MIO31_MASK; XFsbl_Out32(GPIO_DATA_1, RegVal); } }
/** * This function is called in FSBL error cases. Error status * register is updated and fallback is applied * * @param ErrorStatus is the error code which is written to the * error status register * * @return none * * @note Fallback is applied only for fallback supported bootmodes *****************************************************************************/ void XFsbl_ErrorLockDown(u32 ErrorStatus) { u32 BootMode=0U; /** * Print the FSBL error */ XFsbl_Printf(DEBUG_GENERAL,"Fsbl Error Status: 0x%08lx\r\n", ErrorStatus); /** * Update the error status register * and Fsbl instance structure */ XFsbl_Out32(XFSBL_ERROR_STATUS_REGISTER_OFFSET, ErrorStatus); FsblInstancePtr.ErrorCode = ErrorStatus; /** * Read Boot Mode register */ BootMode = XFsbl_In32(CRL_APB_BOOT_MODE_USER) & CRL_APB_BOOT_MODE_USER_BOOT_MODE_MASK; /** * Fallback if bootmode supports */ if ( (BootMode == XFSBL_QSPI24_BOOT_MODE) || (BootMode == XFSBL_QSPI32_BOOT_MODE) || (BootMode == XFSBL_NAND_BOOT_MODE) || (BootMode == XFSBL_SD0_BOOT_MODE) || (BootMode == XFSBL_EMMC_BOOT_MODE) || (BootMode == XFSBL_SD1_BOOT_MODE) || (BootMode == XFSBL_SD1_LS_BOOT_MODE) ) { XFsbl_FallBack(); } else { /** * Be in while loop if fallback is not supported */ XFsbl_Printf(DEBUG_GENERAL,"Fallback not supported \n\r"); /** * Exit FSBL */ XFsbl_HandoffExit(0U, XFSBL_NO_HANDOFFEXIT); } /** * Should never be here */ return ; }
void XFsbl_UpdateMultiBoot(u32 MultiBootValue) { u32 RegValue; XFsbl_Out32(CSU_CSU_MULTI_BOOT, MultiBootValue); /* make sure every thing completes */ dsb(); isb(); /* Soft reset the system */ XFsbl_Printf(DEBUG_GENERAL,"Performing System Soft Reset\n\r"); RegValue = XFsbl_In32(CRL_APB_RESET_CTRL); XFsbl_Out32(CRL_APB_RESET_CTRL, RegValue|CRL_APB_RESET_CTRL_SOFT_RESET_MASK); /* wait here until reset happens */ while(1); return; }
static u32 XFsbl_ResetValidation(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; u32 FsblErrorStatus=0U; u32 ResetReasonValue=0U; u32 ErrStatusRegValue; /** * Read the Error Status register * If WDT reset, do fallback */ FsblErrorStatus = XFsbl_In32(XFSBL_ERROR_STATUS_REGISTER_OFFSET); ResetReasonValue = XFsbl_In32(CRL_APB_RESET_REASON); ErrStatusRegValue = XFsbl_In32(PMU_GLOBAL_ERROR_STATUS_1); /** * Check if the reset is due to system WDT during * previous FSBL execution */ if (((ResetReasonValue & CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK) == CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK) && ((ErrStatusRegValue & PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK) == PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK) && (FsblErrorStatus == XFSBL_RUNNING)) { /** * reset is due to System WDT. * Do a fallback */ Status = XFSBL_ERROR_SYSTEM_WDT_RESET; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_SYSTEM_WDT_RESET\n\r"); goto END; } /** * Mark FSBL running in error status register to * detect the WDT reset while FSBL execution */ if (FsblErrorStatus != XFSBL_RUNNING) { XFsbl_Out32(XFSBL_ERROR_STATUS_REGISTER_OFFSET, XFSBL_RUNNING); } /** * Read system error status register * provide FsblHook function for any action */ END: return Status; }
/** * * This function is used to request isolation restore, through PMU * * @param Mask of the entries for which isolation is to be restored * * @return XFSBL_SUCCESS (for now always returns this) * * @note None. * ****************************************************************************/ u32 XFsbl_IsolationRestore(u32 IsolationMask) { u32 RegVal; u32 Status = XFSBL_SUCCESS; /* Skip power-up request for QEMU */ if (XGet_Zynq_UltraMp_Platform_info() != (u32)XPLAT_ZYNQ_ULTRA_MPQEMU) { /* Isolation request enable */ XFsbl_Out32(PMU_GLOBAL_REQ_ISO_INT_EN, IsolationMask); /* Trigger Isolation request */ XFsbl_Out32(PMU_GLOBAL_REQ_ISO_TRIG, IsolationMask); /* Poll for Isolation complete */ do { RegVal = XFsbl_In32(PMU_GLOBAL_REQ_ISO_STATUS) & IsolationMask; } while (RegVal != 0x0U); } return Status; }
/** * This function is used to get the Reset Reason * * @param None * * @return Reset Reason * * @note * *****************************************************************************/ static u32 XFsbl_GetResetReason (void) { u32 Val; u32 Ret = 0; Val = XFsbl_In32(CRL_APB_RESET_REASON); if (Val & CRL_APB_RESET_REASON_PSONLY_RESET_REQ_MASK) { /* Clear the PS Only reset bit as it is sticky */ Val = CRL_APB_RESET_REASON_PSONLY_RESET_REQ_MASK; XFsbl_Out32(CRL_APB_RESET_REASON, Val); Ret = PS_ONLY_RESET; } return Ret; }
/** * This function checks if PMU FW is loaded and gives handoff to PMU Microblaze * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @param PartitionNum is the partition number of the image * * @return None * *****************************************************************************/ static void XFsbl_CheckPmuFw(XFsblPs * FsblInstancePtr, u32 PartitionNum) { u32 DestinationDev; u32 DestinationDevNxt = 0; u32 PmuFwLoadDone = FALSE; DestinationDev = XFsbl_GetDestinationDevice( &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]); if (DestinationDev == XIH_PH_ATTRB_DEST_DEVICE_PMU) { if ((PartitionNum + 1) < (FsblInstancePtr-> ImageHeader.ImageHeaderTable.NoOfPartitions-1U)) { DestinationDevNxt = XFsbl_GetDestinationDevice( &FsblInstancePtr-> ImageHeader.PartitionHeader[PartitionNum + 1]); if (DestinationDevNxt != XIH_PH_ATTRB_DEST_DEVICE_PMU) { /* there is a partition after this but that is not PMU FW */ PmuFwLoadDone = TRUE; } } else { /* the current partition is last PMU FW partition */ PmuFwLoadDone = TRUE; } } /* If all partitions of PMU FW loaded, handoff it to PMU MicroBlaze */ if (TRUE == PmuFwLoadDone) { /* 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_FW_IS_PRESENT_MASK) != PMU_GLOBAL_GLOBAL_CNTRL_FW_IS_PRESENT_MASK ) {;} } }
void XFsbl_EccInitialize(u32 Address, u32 Length) { u32 Index=0U; /* Disable cache to ensure proper ECC initialization */ Xil_DCacheDisable(); while (Index<Length) { XFsbl_Out32(Address+Index, 1U) ; Index += 4U; } Xil_DCacheEnable(); XFsbl_Printf(DEBUG_INFO, "Address 0x%0lx, Length %0lx, ECC initialized \r\n", Address, Length); return ; }
/** * This function waits for PL Done bit to be set or till timeout and resets * PCAP after this. * * @param None * * @return error status based on implemented functionality (SUCCESS by default) * *****************************************************************************/ u32 XFsbl_PLWaitForDone(void) { u32 Status = XFSBL_SUCCESS; u32 PollCount; u32 RegVal; PollCount = (PL_DONE_POLL_COUNT); while (PollCount) { /* Read PCAP Status register and check for PL_DONE bit */ RegVal = XFsbl_In32(CSU_PCAP_STATUS); RegVal &= CSU_PCAP_STATUS_PL_DONE_MASK; if (RegVal == CSU_PCAP_STATUS_PL_DONE_MASK) { break; } PollCount--; } if (RegVal == CSU_PCAP_STATUS_PL_DONE_MASK) { XFsbl_Printf(DEBUG_GENERAL, "PL Configuration done successfully \r\n"); } else { Status = XFSBL_ERROR_BITSTREAM_LOAD_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_BITSTREAM_LOAD_FAIL\r\n"); goto END; } /* Reset PCAP after data transfer */ RegVal = XFsbl_In32(CSU_PCAP_RESET); RegVal = RegVal | CSU_PCAP_RESET_RESET_MASK; XFsbl_Out32(CSU_PCAP_RESET, RegVal); do { RegVal = XFsbl_In32(CSU_PCAP_RESET); RegVal = RegVal & CSU_PCAP_RESET_RESET_MASK; } while (RegVal != CSU_PCAP_RESET_RESET_MASK); END: return Status; }
/** * This function is used to initialize the system * * @param None * * @return None * *****************************************************************************/ u32 XFsbl_InitWdt(void) { s32 Status; u32 UStatus; XWdtPs_Config *ConfigPtr; /* Config structure of the WatchDog Timer */ u32 CounterValue; u32 RegValue; /** * Initialize the WDT timer */ ConfigPtr = XWdtPs_LookupConfig(XFSBL_WDT_DEVICE_ID); if(ConfigPtr==NULL) { UStatus = XFSBL_WDT_INIT_FAILED; goto END; } Status = XWdtPs_CfgInitialize(&Watchdog, ConfigPtr, ConfigPtr->BaseAddress); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_INFO, "XFSBL_WDT_INIT_FAILED\n\r"); UStatus = XFSBL_WDT_INIT_FAILED; goto END; } /** * Setting the divider value */ XWdtPs_SetControlValue(&Watchdog, XWDTPS_CLK_PRESCALE, XWDTPS_CCR_PSCALE_4096); /** * Convert time to Watchdog counter reset value */ CounterValue = XFsbl_ConvertTime_WdtCounter(XFSBL_WDT_EXPIRE_TIME); /** * Set the Watchdog counter reset value */ XWdtPs_SetControlValue(&Watchdog, XWDTPS_COUNTER_RESET, CounterValue); /** * enable reset output, as we are only using this as a basic counter */ XWdtPs_EnableOutput(&Watchdog, XWDTPS_RESET_SIGNAL); /* Enable generation of system reset by PMU due to LPD SWDT */ RegValue = XFsbl_In32(PMU_GLOBAL_ERROR_SRST_EN_1); RegValue |= PMU_GLOBAL_ERROR_SRST_EN_1_LPD_SWDT_MASK; XFsbl_Out32(PMU_GLOBAL_ERROR_SRST_EN_1, RegValue); /* Enable LPD System Watchdog Timer Error */ RegValue = XFsbl_In32(PMU_GLOBAL_ERROR_EN_1); RegValue |= PMU_GLOBAL_ERROR_EN_1_LPD_SWDT_MASK; XFsbl_Out32(PMU_GLOBAL_ERROR_EN_1, RegValue); /** * Start the Watchdog timer */ XWdtPs_Start(&Watchdog); XWdtPs_RestartWdt(&Watchdog); UStatus = XFSBL_SUCCESS; END: return UStatus; }
/** * * @param * * @return * * @note * * *****************************************************************************/ static void XFsbl_UpdateResetVector (u64 HandOffAddress, u32 CpuSettings, u32 HandoffType, u32 Vector) { u32 HandOffAddressLow; u32 HandOffAddressHigh; u32 LowAddressReg; u32 HighAddressReg; u32 CpuId; u32 RegVal; u32 ExecState; CpuId = CpuSettings & XIH_PH_ATTRB_DEST_CPU_MASK; ExecState = CpuSettings & XIH_PH_ATTRB_A53_EXEC_ST_MASK; /** * Put R5 or A53-32 in Lovec/Hivec */ if ((CpuId == XIH_PH_ATTRB_DEST_CPU_R5_0) || (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_L)) { RegVal = XFsbl_In32(RPU_RPU_0_CFG); RegVal &= ~RPU_RPU_0_CFG_VINITHI_MASK; RegVal |= (Vector << RPU_RPU_0_CFG_VINITHI_SHIFT); XFsbl_Out32(RPU_RPU_0_CFG, RegVal); } else if ((CpuId == XIH_PH_ATTRB_DEST_CPU_R5_1) || (CpuId == XIH_PH_ATTRB_DEST_CPU_R5_L)) { RegVal = XFsbl_In32(RPU_RPU_1_CFG); RegVal &= ~RPU_RPU_1_CFG_VINITHI_MASK; RegVal |= (Vector << RPU_RPU_1_CFG_VINITHI_SHIFT); XFsbl_Out32(RPU_RPU_1_CFG, RegVal); } else if ((CpuId == XIH_PH_ATTRB_DEST_CPU_A53_0) && (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32)) { RegVal = XFsbl_In32(APU_CONFIG_0); RegVal &= ~APU_CONFIG_0_VINITHI_MASK_CPU0; RegVal |= (Vector << APU_CONFIG_0_VINITHI_SHIFT_CPU0); XFsbl_Out32(APU_CONFIG_0, RegVal); } else if ((CpuId == XIH_PH_ATTRB_DEST_CPU_A53_1) && (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32)) { RegVal = XFsbl_In32(APU_CONFIG_0); RegVal &= ~APU_CONFIG_0_VINITHI_MASK_CPU1; RegVal |= (Vector << APU_CONFIG_0_VINITHI_SHIFT_CPU1); XFsbl_Out32(APU_CONFIG_0, RegVal); } else if ((CpuId == XIH_PH_ATTRB_DEST_CPU_A53_2) && (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32)) { RegVal = XFsbl_In32(APU_CONFIG_0); RegVal &= ~APU_CONFIG_0_VINITHI_MASK_CPU2; RegVal |= (Vector << APU_CONFIG_0_VINITHI_SHIFT_CPU2); XFsbl_Out32(APU_CONFIG_0, RegVal); } else if ((CpuId == XIH_PH_ATTRB_DEST_CPU_A53_3) && (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32)) { RegVal = XFsbl_In32(APU_CONFIG_0); RegVal &= ~APU_CONFIG_0_VINITHI_MASK_CPU3; RegVal |= (Vector << APU_CONFIG_0_VINITHI_SHIFT_CPU3); XFsbl_Out32(APU_CONFIG_0, RegVal); } else { /* for MISRA C compliance */ } if ((XFsbl_Is32BitCpu(CpuSettings)==FALSE) && (HandoffType != A53_0_32_HANDOFF_TO_A53_0_64)) { /** * for A53 cpu, write 64bit handoff address * to the RVBARADDR in APU */ HandOffAddressLow = (u32 )(HandOffAddress & 0xFFFFFFFFU); HandOffAddressHigh = (u32 )((HandOffAddress>>32) & 0xFFFFFFFFU); switch (CpuId) { case XIH_PH_ATTRB_DEST_CPU_A53_0: LowAddressReg = APU_RVBARADDR0L; HighAddressReg = APU_RVBARADDR0H; break; case XIH_PH_ATTRB_DEST_CPU_A53_1: LowAddressReg = APU_RVBARADDR1L; HighAddressReg = APU_RVBARADDR1H; break; case XIH_PH_ATTRB_DEST_CPU_A53_2: LowAddressReg = APU_RVBARADDR2L; HighAddressReg = APU_RVBARADDR2H; break; case XIH_PH_ATTRB_DEST_CPU_A53_3: LowAddressReg = APU_RVBARADDR3L; HighAddressReg = APU_RVBARADDR3H; break; default: /** * error can be triggered here */ LowAddressReg = 0U; HighAddressReg = 0U; break; } XFsbl_Out32(LowAddressReg, HandOffAddressLow); XFsbl_Out32(HighAddressReg, HandOffAddressHigh); }
static u32 XFsbl_SetCpuPwrSettings (u32 CpuSettings, u32 Flags) { u32 RegValue; u32 Status; u32 CpuId; u32 ExecState; u32 PwrStateMask; /** * Reset the CPU */ if ((Flags & XFSBL_CPU_SWRST) != 0U) { CpuId = CpuSettings & XIH_PH_ATTRB_DEST_CPU_MASK; ExecState = CpuSettings & XIH_PH_ATTRB_A53_EXEC_ST_MASK; switch(CpuId) { case XIH_PH_ATTRB_DEST_CPU_A53_0: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU0_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_0_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_0_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU0); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU0_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_1: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU1_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_1_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_1_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU1); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU1_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU1_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_2: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU2_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_2_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_2_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU2); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU2_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU2_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_A53_3: PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU3_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_A53_3_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_A53_3_POWER_UP\r\n"); goto END; } /** * Set to Aarch32 if enabled */ if (ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { RegValue = XFsbl_In32(APU_CONFIG_0); RegValue &= ~(APU_CONFIG_0_AA64N32_MASK_CPU3); XFsbl_Out32(APU_CONFIG_0, RegValue); } /** * Enable the clock */ RegValue = XFsbl_In32(CRF_APB_ACPU_CTRL); RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK); XFsbl_Out32(CRF_APB_ACPU_CTRL, RegValue); /** * Release reset */ RegValue = XFsbl_In32(CRF_APB_RST_FPD_APU); RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU3_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU3_PWRON_RESET_MASK); XFsbl_Out32(CRF_APB_RST_FPD_APU, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_0: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_0_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_0_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_0_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= (RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= (CRL_APB_CPU_R5_CTRL_CLKACT_MASK); XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-0 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-0 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue |= RPU_RPU_0_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_0_CFG, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_1: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_1_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_1_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_1_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-1 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue |= RPU_RPU_1_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_1_CFG, RegValue); break; case XIH_PH_ATTRB_DEST_CPU_R5_L: Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_R5_0_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_L_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_L_POWER_UP\r\n"); goto END; } /** * Place R5, TCM's in safe mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue |= RPU_RPU_GLBL_CNTL_TCM_COMB_MASK; RegValue |= RPU_RPU_GLBL_CNTL_SLCLAMP_MASK; XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-0, R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); /** * Take R5-0 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue |= RPU_RPU_0_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Take R5-1 out of HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue |= RPU_RPU_1_CFG_NCPUHALT_MASK; XFsbl_Out32(RPU_RPU_1_CFG, RegValue); break; default: XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HANDOFF_CPUID\n\r"); Status = XFSBL_ERROR_HANDOFF_CPUID; break; } } else { Status = XFSBL_SUCCESS; } END: return Status; }
/** * This function validates the partition * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @param PartitionNum is the partition number in the image to be loaded * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * *****************************************************************************/ static u32 XFsbl_PartitionValidation(XFsblPs * FsblInstancePtr, u32 PartitionNum) { u32 Status=XFSBL_SUCCESS; u32 ChecksumType=0U; s32 IsEncryptionEnabled=FALSE; s32 IsAuthenticationEnabled=FALSE; u32 DestinationDevice=0U; u32 DestinationCpu=0U; u32 ExecState=0U; u32 CpuNo=0U; XFsblPs_PartitionHeader * PartitionHeader; #if defined(XFSBL_RSA) u32 HashLen=0U; #endif #if defined(XFSBL_AES) u32 ImageOffset = 0U; u32 FsblIv[XIH_BH_IV_LENGTH / 4U]; u32 UnencryptedLength = 0; u32 IvLocation; #endif #if defined(XFSBL_RSA) || defined(XFSBL_AES) u32 Length=0U; #endif #if defined(XFSBL_RSA) || defined(XFSBL_AES) || defined(XFSBL_BS) PTRSIZE LoadAddress=0U; #endif #if defined(XFSBL_BS) u32 BitstreamWordSize = 0; #endif /** * Update the variables */ PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; ChecksumType = XFsbl_GetChecksumType(PartitionHeader); /** * Check the encryption status */ if (XFsbl_IsEncrypted(PartitionHeader) == XIH_PH_ATTRB_ENCRYPTION ) { IsEncryptionEnabled = TRUE; #ifdef XFSBL_AES /* Copy the Iv from Flash into local memory */ IvLocation = ImageOffset + XIH_BH_IV_OFFSET; Status = FsblInstancePtr->DeviceOps.DeviceCopy(IvLocation, (PTRSIZE) FsblIv, XIH_BH_IV_LENGTH); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_DECRYPTION_IV_COPY_FAIL \r\n"); Status = XFSBL_ERROR_DECRYPTION_IV_COPY_FAIL; goto END; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_AES_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_AES_NOT_ENABLED; goto END; #endif } /** * check the authentication status */ if (XFsbl_IsRsaSignaturePresent(PartitionHeader) == XIH_PH_ATTRB_RSA_SIGNATURE ) { IsAuthenticationEnabled = TRUE; } DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); DestinationCpu = XFsbl_GetDestinationCpu(PartitionHeader); /** * Get the execution state */ ExecState = XFsbl_GetA53ExecState(PartitionHeader); /** * if destination cpu is not present, it means it is for same cpu */ if (DestinationCpu == XIH_PH_ATTRB_DEST_CPU_NONE) { DestinationCpu = FsblInstancePtr->ProcessorID; } /** * Checksum Validation */ if (ChecksumType == XIH_PH_ATTRB_CHECKSUM_MD5) { /** * Do the checksum validation */ } #if defined(XFSBL_RSA) || defined(XFSBL_AES) if ((IsAuthenticationEnabled == TRUE) || (IsEncryptionEnabled == TRUE)) { LoadAddress = PartitionHeader->DestinationLoadAddress; Length = PartitionHeader->TotalDataWordLength * 4U; Status = XFsbl_GetLoadAddress(DestinationCpu, &LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } } #endif #ifdef XFSBL_BS if ((DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) && (LoadAddress == 0U)) { LoadAddress = XFSBL_DDR_TEMP_ADDRESS; } #endif /** * Authentication Check */ if (IsAuthenticationEnabled == TRUE) { XFsbl_Printf(DEBUG_INFO,"Authentication Enabled\r\n"); #ifdef XFSBL_RSA /** * Get the Sha type to be used from * boot header attributes */ if ((FsblInstancePtr->BootHdrAttributes & XIH_BH_IMAGE_ATTRB_SHA2_MASK) == XIH_BH_IMAGE_ATTRB_SHA2_MASK) { HashLen = XFSBL_HASH_TYPE_SHA2; } else { HashLen = XFSBL_HASH_TYPE_SHA3; } /** * cache disbale can be removed */ Xil_DCacheDisable(); /** * Do the authentication validation */ Status = XFsbl_Authentication(FsblInstancePtr, LoadAddress, Length, (LoadAddress + Length) - XFSBL_AUTH_CERT_MIN_SIZE, HashLen); if (Status != XFSBL_SUCCESS) { goto END; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_RSA_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_RSA_NOT_ENABLED; goto END; #endif } /** * Decrypt image through CSU DMA */ if (IsEncryptionEnabled == TRUE) { XFsbl_Printf(DEBUG_INFO, "Decryption Enabled\r\n"); #ifdef XFSBL_AES /* AES expects IV in big endian form */ FsblIv[0] = Xil_Htonl(FsblIv[0]); FsblIv[1] = Xil_Htonl(FsblIv[1]); FsblIv[2] = Xil_Htonl(FsblIv[2]); /* Initialize the Aes Instance so that it's ready to use */ XSecure_AesInitialize(&SecureAes, &CsuDma, XSECURE_CSU_AES_KEY_SRC_DEV, FsblIv, NULL); XFsbl_Printf(DEBUG_INFO, " Aes initialized \r\n"); UnencryptedLength = PartitionHeader->UnEncryptedDataWordLength * 4U; if (DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PL) { Status = XSecure_AesDecrypt(&SecureAes, (u8 *) LoadAddress, (u8 *) LoadAddress, UnencryptedLength); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_DECRYPTION_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_DECRYPTION_FAIL\r\n"); goto END; } else { XFsbl_Printf(DEBUG_GENERAL, "Decryption Successful\r\n"); } } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_AES_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_AES_NOT_ENABLED; goto END; #endif } #ifdef XFSBL_BS /** * for PL image use CSU DMA to route to PL */ if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { /** * Fsbl hook before bit stream download */ Status = XFsbl_HookBeforeBSDownload(); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_HOOK_BEFORE_BITSTREAM_DOWNLOAD; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HOOK_BEFORE_BITSTREAM_DOWNLOAD\r\n"); goto END; } XFsbl_Printf(DEBUG_GENERAL, "Bitstream download to start now\r\n"); Status = XFsbl_PcapInit(); if (Status != XFSBL_SUCCESS) { goto END; } if (IsEncryptionEnabled == TRUE) { #ifdef XFSBL_AES /* * The secure bitstream would be sent through CSU DMA to AES * and the decrypted bitstream is sent directly to PCAP * by configuring SSS appropriately */ Status = XSecure_AesDecrypt(&SecureAes, (u8 *) XFSBL_DESTINATION_PCAP_ADDR, (u8 *) LoadAddress, UnencryptedLength); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_BITSTREAM_DECRYPTION_FAIL; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_BITSTREAM_DECRYPTION_FAIL\r\n"); /* Reset PL */ XFsbl_Out32(CSU_PCAP_PROG, 0x0); goto END; } else { XFsbl_Printf(DEBUG_GENERAL, "Bitstream decryption Successful\r\n"); } #endif } else { /* Use CSU DMA to load Bit stream to PL */ BitstreamWordSize = PartitionHeader->UnEncryptedDataWordLength; Status = XFsbl_WriteToPcap(BitstreamWordSize, (u8 *) LoadAddress); if (Status != XFSBL_SUCCESS) { goto END; } } Status = XFsbl_PLWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } /** * Fsbl hook after bit stream download */ Status = XFsbl_HookAfterBSDownload(); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_HOOK_AFTER_BITSTREAM_DOWNLOAD; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_HOOK_AFTER_BITSTREAM_DOWNLOAD\r\n"); goto END; } } #endif /** * Update the handoff details */ if ((DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PL) && (DestinationDevice != XIH_PH_ATTRB_DEST_DEVICE_PMU)) { CpuNo = FsblInstancePtr->HandoffCpuNo; if (XFsbl_CheckHandoffCpu(FsblInstancePtr, DestinationCpu) == XFSBL_SUCCESS) { FsblInstancePtr->HandoffValues[CpuNo].CpuSettings = DestinationCpu | ExecState; FsblInstancePtr->HandoffValues[CpuNo].HandoffAddress = PartitionHeader->DestinationExecutionAddress; FsblInstancePtr->HandoffCpuNo += 1U; } } END: return Status; }
/** * This function copies the partition to specified destination * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @param PartitionNum is the partition number in the image to be loaded * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success *****************************************************************************/ static u32 XFsbl_PartitionCopy(XFsblPs * FsblInstancePtr, u32 PartitionNum) { u32 Status=XFSBL_SUCCESS; u32 DestinationCpu=0U; u32 CpuNo=0U; u32 DestinationDevice=0U; u32 ExecState=0U; XFsblPs_PartitionHeader * PartitionHeader; u32 SrcAddress=0U; PTRSIZE LoadAddress=0U; u32 Length=0U; u32 RunningCpu=0U; /** * Assign the partition header to local variable */ PartitionHeader = &FsblInstancePtr->ImageHeader.PartitionHeader[PartitionNum]; RunningCpu = FsblInstancePtr->ProcessorID; /** * Check for XIP image * No need to copy for XIP image */ DestinationCpu = XFsbl_GetDestinationCpu(PartitionHeader); /** * Get the execution state */ ExecState = XFsbl_GetA53ExecState(PartitionHeader); /** * if destination cpu is not present, it means it is for same cpu */ if (DestinationCpu == XIH_PH_ATTRB_DEST_CPU_NONE) { DestinationCpu = FsblInstancePtr->ProcessorID; } if (PartitionHeader->UnEncryptedDataWordLength == 0U) { /** * Update the Handoff address only for the first application * of that cpu * This is for XIP image. For other partitions it handoff * address is updated after partition validation */ CpuNo = FsblInstancePtr->HandoffCpuNo; if (XFsbl_CheckHandoffCpu(FsblInstancePtr, DestinationCpu) == XFSBL_SUCCESS) { FsblInstancePtr->HandoffValues[CpuNo].CpuSettings = DestinationCpu | ExecState; FsblInstancePtr->HandoffValues[CpuNo].HandoffAddress = PartitionHeader->DestinationExecutionAddress; FsblInstancePtr->HandoffCpuNo += 1U; } else { /** * * if two partitions has same destination cpu, error can * be triggered here */ } Status = XFSBL_SUCCESS; goto END; } /** * Copy the PL to temporary DDR Address * Copy the PS to Load Address * Copy the PMU firmware to PMU RAM */ DestinationDevice = XFsbl_GetDestinationDevice(PartitionHeader); LoadAddress = PartitionHeader->DestinationLoadAddress; if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PL) { #ifdef XFSBL_BS if (LoadAddress == XFSBL_DUMMY_PL_ADDR) { LoadAddress = XFSBL_DDR_TEMP_ADDRESS; } #else XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_PL_NOT_ENABLED \r\n"); Status = XFSBL_ERROR_PL_NOT_ENABLED; goto END; #endif } /** * Get the source(flash offset) address where it needs to copy */ SrcAddress = FsblInstancePtr->ImageOffsetAddress + ((PartitionHeader->DataWordOffset) * XIH_PARTITION_WORD_LENGTH); /** * Length of the partition to be copied */ Length = (PartitionHeader->TotalDataWordLength) * XIH_PARTITION_WORD_LENGTH; /** * When destination device is R5-0/R5-1/R5-L and load address is in TCM * copy to high address of TCM address map * Update the LoadAddress */ Status = XFsbl_GetLoadAddress(DestinationCpu, &LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } /** * Configure the memory */ XFsbl_ConfigureMemory(RunningCpu, DestinationCpu, LoadAddress, Length); /** * * Do not copy the IVT if FSBL is running in R5-0/R5-L at 0x0 TCM * Update the SrcAddress, LoadAddress and Len based on the * above condition */ #if 1 if (((FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_0) || (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_L)) && ((LoadAddress > XFSBL_R50_HIGH_TCM_START_ADDRESS) && (LoadAddress < XFSBL_R50_HIGH_TCM_START_ADDRESS + XFSBL_IVT_LENGTH))) { /** * Get the length of the IVT area to be * skipped from Load Address */ TcmSkipAddress = LoadAddress/XFSBL_IVT_LENGTH; TcmSkipLength = XFSBL_IVT_LENGTH - TcmSkipAddress; /** * Check if Length is less than SkipLength */ if (TcmSkipLength > Length) { TcmSkipLength = Length; } /** * Copy the Skip length to a local array */ Status = FsblInstancePtr->DeviceOps.DeviceCopy(SrcAddress, (PTRSIZE )TcmVectorArray, TcmSkipLength); if (XFSBL_SUCCESS != Status) { goto END; } SrcAddress += TcmSkipLength; LoadAddress += TcmSkipLength; Length -= TcmSkipLength; } #endif if (DestinationDevice == XIH_PH_ATTRB_DEST_DEVICE_PMU) { /* Enable PMU_0 IPI */ XFsbl_Out32(IPI_PMU_0_IER, IPI_PMU_0_IER_PMU_0_MASK); /* Trigger PMU0 IPI in PMU IPI TRIG Reg */ XFsbl_Out32(IPI_PMU_0_TRIG, IPI_PMU_0_TRIG_PMU_0_MASK); /** * 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 */ Status = FsblInstancePtr->DeviceOps.DeviceCopy(SrcAddress, LoadAddress, Length); if (XFSBL_SUCCESS != Status) { goto END; } END: return Status; }
/** * This function initializes the system using the psu_init() * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_SystemInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; #if defined (XPAR_PSU_DDR_0_S_AXI_BASEADDR) && !defined (ARMR5) u32 BlockNum; #endif /** * MIO33 can be used to control power to PL through PMU. * For 1.0 and 2.0 Silicon, a workaround is needed to Powerup PL * before MIO33 is configured. Hence, before MIO configuration, * Powerup PL (but restore isolation). */ if (XGetPSVersion_Info() <= XPS_VERSION_2) { Status = XFsbl_PowerUpIsland(PMU_GLOBAL_PWR_STATE_PL_MASK); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_PL_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_PL_POWER_UP\r\n"); goto END; } /* For PS only reset, make sure FSBL exits with isolation removed */ if (FsblInstancePtr->ResetReason != PS_ONLY_RESET) { XFsbl_IsolationRestore(PMU_GLOBAL_REQ_ISO_INT_EN_PL_NONPCAP_MASK); } } /** * psu initialization */ Status = (u32)psu_init(); if (XFSBL_SUCCESS != Status) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_PSU_INIT_FAILED\n\r"); /** * Need to check a way to communicate both FSBL code * and PSU init error code */ Status = XFSBL_PSU_INIT_FAILED + Status; goto END; } #ifdef XFSBL_PERF XTime_GetTime(&(FsblInstancePtr->PerfTime.tFsblStart)); #endif #if defined (XPAR_PSU_DDR_0_S_AXI_BASEADDR) && !defined (ARMR5) /* For A53, mark DDR region as "Memory" as DDR initialization is done */ #ifdef ARMA53_64 /* For A53 64bit*/ for(BlockNum = 0; BlockNum < NUM_BLOCKS_A53_64; BlockNum++) { XFsbl_SetTlbAttributes(BlockNum * BLOCK_SIZE_A53_64, ATTRIB_MEMORY_A53_64); } Xil_DCacheFlush(); #else /* For A53 32bit*/ for(BlockNum = 0; BlockNum < NUM_BLOCKS_A53_32; BlockNum++) { XFsbl_SetTlbAttributes(BlockNum * BLOCK_SIZE_A53_32, ATTRIB_MEMORY_A53_32); } Xil_DCacheFlush(); #endif #endif /** * Forcing the SD card detection signal to bypass the debouncing logic. * This will ensure that SD controller doesn't end up waiting for long, * fixed durations for card to be stable. */ XFsbl_Out32(IOU_SLCR_SD_CDN_CTRL, (IOU_SLCR_SD_CDN_CTRL_SD1_CDN_CTRL_MASK | IOU_SLCR_SD_CDN_CTRL_SD0_CDN_CTRL_MASK)); /** * DDR Check if present */ /** * Poweroff the unused blocks as per PSU */ END: return Status; }
/** * This function checks the power state and reset for the memory type * and release the reset if required * * @param MemoryType is the memory to be checked * - XFSBL_R5_0_TCM * - XFSBL_R5_1_TCM * (to be added) * - XFSBL_R5_0_TCMA * - XFSBL_R5_0_TCMB * - XFSBL_PS_DDR * - XFSBL_PL_DDR * * @return none *****************************************************************************/ static u32 XFsbl_PowerUpMemory(u32 MemoryType) { u32 RegValue; u32 Status = XFSBL_SUCCESS; u32 PwrStateMask; /** * Check the power status of the memory * Power up if required * * Release the reset of the memory if present */ switch (MemoryType) { case XFSBL_R5_0_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_0_MASK | PMU_GLOBAL_PWR_STATE_TCM0A_MASK | PMU_GLOBAL_PWR_STATE_TCM0B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_0_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_0_TCM_POWER_UP\r\n"); goto END; } /** * To access TCM, * Release reset to R5 and enable the clk * R5 is under halt state * * If R5 are out of reset and clk is enabled so doing * again is no issue. R5 might be under running state */ /** * Place R5, TCM in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void)usleep(0x50U); /** * Release reset to R5-0 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; case XFSBL_R5_1_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_1_MASK | PMU_GLOBAL_PWR_STATE_TCM1A_MASK | PMU_GLOBAL_PWR_STATE_TCM1B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_1_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_1_TCM_POWER_UP\r\n"); goto END; } /** * Place R5 in split mode */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLSPLIT_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_TCM_COMB_MASK); RegValue &= ~(RPU_RPU_GLBL_CNTL_SLCLAMP_MASK); XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; case XFSBL_R5_L_TCM: { PwrStateMask = PMU_GLOBAL_PWR_STATE_R5_0_MASK | PMU_GLOBAL_PWR_STATE_TCM0A_MASK | PMU_GLOBAL_PWR_STATE_TCM0B_MASK | PMU_GLOBAL_PWR_STATE_TCM1A_MASK | PMU_GLOBAL_PWR_STATE_TCM1B_MASK; Status = XFsbl_PowerUpIsland(PwrStateMask); if (Status != XFSBL_SUCCESS) { Status = XFSBL_ERROR_R5_L_TCM_POWER_UP; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_R5_L_TCM_POWER_UP\r\n"); goto END; } /** * Place R5 in lock step mode * Combine TCM's */ RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); RegValue |= RPU_RPU_GLBL_CNTL_SLCLAMP_MASK; RegValue &= ~(RPU_RPU_GLBL_CNTL_SLSPLIT_MASK); RegValue |= RPU_RPU_GLBL_CNTL_TCM_COMB_MASK; XFsbl_Out32(RPU_RPU_GLBL_CNTL, RegValue); /** * Place R5-0 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_0_CFG); RegValue &= ~(RPU_RPU_0_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_0_CFG, RegValue); /** * Place R5-1 in HALT state */ RegValue = XFsbl_In32(RPU_RPU_1_CFG); RegValue &= ~(RPU_RPU_1_CFG_NCPUHALT_MASK); XFsbl_Out32(RPU_RPU_1_CFG, RegValue); /** * Enable the clock */ RegValue = XFsbl_In32(CRL_APB_CPU_R5_CTRL); RegValue |= CRL_APB_CPU_R5_CTRL_CLKACT_MASK; XFsbl_Out32(CRL_APB_CPU_R5_CTRL, RegValue); /** * Provide some delay, * so that clock propogates properly. */ (void )usleep(0x50U); /** * Release reset to R5-0,R5-1 */ RegValue = XFsbl_In32(CRL_APB_RST_LPD_TOP); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK); RegValue &= ~(CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK); XFsbl_Out32(CRL_APB_RST_LPD_TOP, RegValue); } break; default: /* nothing to do */ break; } END: return Status; }
/****************************************************************************** * * This function copies data memory to memory using ADMA. * * @param DestPtr is a pointer to destination buffer to which data needs * to be copied. * @param SrcPtr is a pointer to the source buffer. * @param size holds the size of the data to be transfered. * * @return * Success on successful copy * Error on failure. * * @note Cache invalidation and flushing should be taken care by user * Before calling this API ADMA also should be configured to * simple DMA. * ******************************************************************************/ u32 XFsbl_AdmaCopy(void * DestPtr, void * SrcPtr, u32 Size) { u32 RegVal; u64 SrcAddr = (UINTPTR)SrcPtr; u64 DstAddr = (UINTPTR)DestPtr; u32 Status = XFSBL_SUCCESS; /* Wait until the DMA is in idle state */ do { RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_STATUS); RegVal &= ADMA_CH0_ZDMA_CH_STATUS_STATE_MASK; } while ((RegVal != ADMA_CH0_ZDMA_CH_STATUS_STATE_DONE) && (RegVal != ADMA_CH0_ZDMA_CH_STATUS_STATE_ERR)); /* Write source Address */ XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD0, (SrcAddr & ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0_LSB_MASK)); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD1, (((u64)SrcAddr >> 32U) & ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1_MSB_MASK)); /* Write Destination Address */ XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0, (u32)(DstAddr & ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0_LSB_MASK)); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1, (u32)((DstAddr >> 32U) & ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1_MSB_MASK)); /* Size to be Transferred. Recommended to set both src and dest sizes */ XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD2, Size); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD2, Size); /* coherence enable */ RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD3); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD3, RegVal | 0x1U); RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD3); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD3, RegVal | 0x1U); /* DMA Enable */ RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_CTRL2); RegVal |= ADMA_CH0_ZDMA_CH_CTRL2_EN_MASK; XFsbl_Out32(ADMA_CH0_ZDMA_CH_CTRL2, RegVal); /* Check the status of the transfer by polling on DMA Done */ do { RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_ISR); RegVal &= ADMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; } while (RegVal != ADMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Clear DMA status */ RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_ISR); RegVal |= ADMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; XFsbl_Out32(ADMA_CH0_ZDMA_CH_ISR, ADMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Read the channel status for errors */ RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_STATUS); if (RegVal == ADMA_CH0_ZDMA_CH_STATUS_STATE_ERR) { Status = XFSBL_FAILURE; } /* Clear the TOTAL BYTE COUNT register to avoid the BYTE_CNT_OVRFLW *interupt from being set */ XFsbl_Out32(ADMA_CH0_ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT,0x00000000U); return Status; }
/****************************************************************************** * * This function re-authenticates the each chunk of the block and compares * with the stored hash and sends the data AES engine if encryption exists * and to PCAP directly in encryption is not existing. * * @param PartitionParams is a pointer to XFsblPs_PlPartition * @param Address start address of the authentication block. * @param BlockLen size of the authentication block. * @param NoOfChunks holds the no of chunks for the provided block * * @return * Error code on failure * XFSBL_SUCESS on success * * @note None. * ******************************************************************************/ static u32 XFsbl_ReAuthenticationBlock(XFsblPs_PlPartition *PartitionParams, UINTPTR Address, u32 BlockLen, u32 NoOfChunks) { u32 Status; u32 Index; u32 Len = PartitionParams->ChunkSize;; UINTPTR Offset; u8 ChunksHash[48]; XSecure_Sha3 SecureSha3; u32 HashDataLen = BlockLen; u8 *HashStored = PartitionParams->PlAuth.HashsOfChunks; (void)memset(ChunksHash,0U,sizeof(ChunksHash)); Status = XSecure_Sha3Initialize(&SecureSha3, PartitionParams->CsuDmaPtr); if (Status != XFSBL_SUCCESS) { return Status; } XSecure_Sha3Start(&SecureSha3); /* calculating hashs for all chunks copies to AES/PCAP */ for (Index = 0; Index < NoOfChunks; Index++) { /* Last chunk */ if (Index == NoOfChunks -1) { Len = HashDataLen; } Offset = (UINTPTR)Address + (u64)(PartitionParams->ChunkSize * Index); /* Copy from DDR or flash to Buffer */ Status = XFsbl_CopyData(PartitionParams, PartitionParams->ChunkBuffer, (u8 *)Offset, Len); if (Status != XFSBL_SUCCESS) { return Status; } /* Calculating hash for each chunk */ XSecure_Sha3Update(&SecureSha3, PartitionParams->ChunkBuffer, Len); XSecure_Sha3_ReadHash(&SecureSha3, (u8 *)ChunksHash); /* Comparing with stored Hashs */ Status = XFsbl_CompareHashs(HashStored, ChunksHash, PartitionParams->PlAuth.AuthType); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PlReAuth:" " XFSBL_ERROR_CHUNK_HASH_COMPARISON\r\n"); XFsbl_PrintArray(DEBUG_INFO, HashStored, PartitionParams->PlAuth.AuthType, "Stored Chunk Hash"); XFsbl_PrintArray(DEBUG_INFO, ChunksHash, PartitionParams->PlAuth.AuthType, "Calculated chunk Hash"); Status = XFSBL_ERROR_CHUNK_HASH_COMPARISON; goto END; } /* Remaining block size will be in HashDataLen */ HashDataLen = HashDataLen - PartitionParams->ChunkSize; if (Index+1 <= NoOfChunks - 1) { HashStored = HashStored + PartitionParams->PlAuth.AuthType; } /* If image is not encrypted */ if (PartitionParams->IsEncrypted == FALSE) { /* Configure Secure stream swith to PCAP */ XFsbl_Out32(CSU_CSU_SSS_CFG, XFSBL_CSU_SSS_SRC_SRC_DMA << CSU_CSU_SSS_CFG_PCAP_SSS_SHIFT); /* Copy bitstream to PCAP */ XFsbl_DmaPlCopy(PartitionParams->CsuDmaPtr, (UINTPTR)PartitionParams->ChunkBuffer, Len/4, 0); Status = XFsbl_PcapWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } } /* If image is encrypted */ else { Status = XFsbl_DecrptPlChunks(PartitionParams, (UINTPTR)PartitionParams->ChunkBuffer, Len); if (Status != XFSBL_SUCCESS) { goto END; } } } END: return Status; }
/** * This function initializes the processor and updates the cluster id * which indicates CPU on which fsbl is running * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_ProcessorInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; //u64 ClusterId=0U; PTRSIZE ClusterId=0U; u32 RegValue; u32 Index=0U; /** * Read the cluster ID and Update the Processor ID * Initialize the processor settings that are not done in * BSP startup code */ #ifdef ARMA53_64 ClusterId = mfcp(MPIDR_EL1); #else ClusterId = mfcp(XREG_CP15_MULTI_PROC_AFFINITY); #endif XFsbl_Printf(DEBUG_INFO,"Cluster ID 0x%0lx\n\r", ClusterId); if (XGet_Zynq_UltraMp_Platform_info() == XPLAT_ZYNQ_ULTRA_MPQEMU) { /** * Remmaping for R5 in QEMU */ if (ClusterId == 0x80000004U) { ClusterId = 0xC0000100U; } else if (ClusterId == 0x80000005U) { /* this corresponds to R5-1 */ Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } else { /* For MISRA C compliance */ } } /* store the processor ID based on the cluster ID */ if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_A53_PROCESSOR) { XFsbl_Printf(DEBUG_GENERAL,"Running on A53-0 "); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_A53_0; #ifdef __aarch64__ /* Running on A53 64-bit */ XFsbl_Printf(DEBUG_GENERAL,"(64-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA64; #else /* Running on A53 32-bit */ XFsbl_Printf(DEBUG_GENERAL,"(32-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA32; #endif } else if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_R5_PROCESSOR) { /* A53ExecState is not valid for R5 */ FsblInstancePtr->A53ExecState = XIH_INVALID_EXEC_ST; RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); if ((RegValue & RPU_RPU_GLBL_CNTL_SLSPLIT_MASK) == 0U) { XFsbl_Printf(DEBUG_GENERAL, "Running on R5 Processor in Lockstep \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_L; } else { XFsbl_Printf(DEBUG_GENERAL, "Running on R5-0 Processor \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_0; } /** * Update the Vector locations in R5 TCM */ while (Index<32U) { XFsbl_Out32(Index, XFSBL_R5_VECTOR_VALUE); Index += 4; } } else { Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } /** * Register the exception handlers */ XFsbl_RegisterHandlers(); /* Prints for the perf measurement */ #ifdef XFSBL_PERF #if !defined(ARMR5) if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_A53_0) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: A53-0 Freq: %d Hz", XPAR_CPU_CORTEXA53_0_CPU_CLK_FREQ_HZ); if (FsblInstancePtr->A53ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA32) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, " Arch: 32 \r\n"); } else if (FsblInstancePtr->A53ExecState == XIH_PH_ATTRB_A53_EXEC_ST_AA64) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, " Arch: 64 \r\n"); } } #else if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_0) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: R5-0 Freq: %d Hz \r\n", XPAR_PSU_CORTEXR5_0_CPU_CLK_FREQ_HZ) } else if (FsblInstancePtr->ProcessorID == XIH_PH_ATTRB_DEST_CPU_R5_L) { XFsbl_Printf(DEBUG_PRINT_ALWAYS, "Proc: R5-Lockstep " "Freq: %d Hz \r\n", XPAR_PSU_CORTEXR5_0_CPU_CLK_FREQ_HZ); } #endif #endif END: return Status; }
/** * This function initializes the processor and updates the cluster id * which indicates CPU on which fsbl is running * * @param FsblInstancePtr is pointer to the XFsbl Instance * * @return returns the error codes described in xfsbl_error.h on any error * returns XFSBL_SUCCESS on success * ******************************************************************************/ static u32 XFsbl_ProcessorInit(XFsblPs * FsblInstancePtr) { u32 Status = XFSBL_SUCCESS; //u64 ClusterId=0U; PTRSIZE ClusterId=0U; u32 RegValue; u32 Index=0U; /** * Read the cluster ID and Update the Processor ID * Initialize the processor settings that are not done in * BSP startup code */ #ifdef XFSBL_A53 ClusterId = mfcp(MPIDR_EL1); #else ClusterId = mfcp(XREG_CP15_MULTI_PROC_AFFINITY); #endif XFsbl_Printf(DEBUG_INFO,"Cluster ID 0x%0lx\n\r", ClusterId); if (XFSBL_PLATFORM == XFSBL_PLATFORM_QEMU) { /** * Remmaping for R5 in QEMU */ if (ClusterId == 0x80000004U) { ClusterId = 0xC0000100U; } else if (ClusterId == 0x80000005U) { /* this corresponds to R5-1 */ Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } else { /* For MISRA C compliance */ } } /* store the processor ID based on the cluster ID */ if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_A53_PROCESSOR) { XFsbl_Printf(DEBUG_GENERAL,"Running on A53-0 "); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_A53_0; #ifdef __aarch64__ /* Running on A53 64-bit */ XFsbl_Printf(DEBUG_GENERAL,"(64-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA64; #else /* Running on A53 32-bit */ XFsbl_Printf(DEBUG_GENERAL,"(32-bit) Processor \n\r"); FsblInstancePtr->A53ExecState = XIH_PH_ATTRB_A53_EXEC_ST_AA32; #endif } else if ((ClusterId & XFSBL_CLUSTER_ID_MASK) == XFSBL_R5_PROCESSOR) { /* A53ExecState is not valid for R5 */ FsblInstancePtr->A53ExecState = XIH_INVALID_EXEC_ST; RegValue = XFsbl_In32(RPU_RPU_GLBL_CNTL); if ((RegValue & RPU_RPU_GLBL_CNTL_SLSPLIT_MASK) == 0U) { XFsbl_Printf(DEBUG_GENERAL, "Running on R5 Processor in Lockstep \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_L; } else { XFsbl_Printf(DEBUG_GENERAL, "Running on R5-0 Processor \n\r"); FsblInstancePtr->ProcessorID = XIH_PH_ATTRB_DEST_CPU_R5_0; } /** * Update the Vector locations in R5 TCM */ while (Index<32U) { XFsbl_Out32(Index, 0U); XFsbl_Out32(Index, XFSBL_R5_VECTOR_VALUE); Index += 4; } } else { Status = XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID; XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_UNSUPPORTED_CLUSTER_ID\n\r"); goto END; } /** * Register the exception handlers */ XFsbl_RegisterHandlers(); END: return Status; }
/** * This function authenticates the bitstream in blocks. Sends the data to PCAP * in blocks via AES engine if encryption exists or directly to PCAP by CSUDMA * if an encryption is not enabled. * * @param PartitionParams is pointer to XFsblPs_PlPartition structure * which has to be initialized by required parameters. * * @return * - XFSBL_SUCCESS on success * - Returns error code on failure * * @note Currently SHA2 is not been supported but gave option in * structure and will be used later * ******************************************************************************/ u32 XFsbl_SecPlPartition(XFsblPs * FsblInstancePtr, XFsblPs_PlPartition *PartitionParams) { u32 Status = XFSBL_SUCCESS; u8 Index; u32 Len; UINTPTR SrcAddress = (u64)PartitionParams->StartAddress; UINTPTR CurrentAcOffset = PartitionParams->PlAuth.AcOfset; u8 IsLastBlock = FALSE; u32 RegVal; if (PartitionParams->IsAuthenticated != TRUE) { XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_SECURE_NOT_ENABLED" " for PL partition\r\n"); Status = XFSBL_ERROR_SECURE_NOT_ENABLED; goto END; } /* AES initialization expects IV in required format */ if (PartitionParams->IsEncrypted == TRUE) { PartitionParams->PlEncrypt.NextBlkLen = 0; if (PartitionParams->PlEncrypt.SecureAes == NULL) { XFsbl_Printf(DEBUG_GENERAL, "XFSBL_ERROR_SECURE_NOT_ENABLED" " for PL partition \r\n"); Status = XFSBL_ERROR_SECURE_NOT_ENABLED; goto END; } if ((PartitionParams->PlEncrypt.SecureAes->KeySel == XSECURE_CSU_AES_KEY_SRC_KUP) && (PartitionParams->PlEncrypt.SecureAes->Key == NULL)) { XFsbl_Printf(DEBUG_GENERAL, "KUP key is not been provided" " for PL partition\r\n"); Status = XFSBL_FAILURE; goto END; } } /* Enable Simple DMA Mode for ADMA channel 0 */ RegVal = XFsbl_In32(ADMA_CH0_ZDMA_CH_CTRL0); RegVal &= (ADMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_MASK | ADMA_CH0_ZDMA_CH_CTRL0_MODE_MASK); XFsbl_Out32(ADMA_CH0_ZDMA_CH_CTRL0, RegVal); Xil_DCacheDisable(); /* Loop for traversing all blocks */ for (Len = PartitionParams->PlAuth.BlockSize, Index = 1; SrcAddress < PartitionParams->PlAuth.AcOfset; Index++) { Status = XFsbl_CopyData(PartitionParams, PartitionParams->PlAuth.AuthCertBuf, (u8 *)CurrentAcOffset, XFSBL_AUTH_CERT_MIN_SIZE); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_GENERAL, "Copy of chunk from flash/DDR to OCM failed \r\n"); return Status; } /* * If the block start address + block size exceeds * first AC address it is last block */ if (SrcAddress + PartitionParams->PlAuth.BlockSize > PartitionParams->PlAuth.AcOfset) { /* * Data placed in last block might not be full block size * TotalLen - * (NoofBlocks)*(AC size) - (NoOfBlocks - 1)*BlockSize */ Len = (PartitionParams->TotalLen) - (Index) * (XFSBL_AUTH_CERT_MIN_SIZE) - (Index -1)*(PartitionParams->PlAuth.BlockSize); IsLastBlock = TRUE; } Status = XFsbl_PlBlockAuthentication(FsblInstancePtr, PartitionParams, SrcAddress, Len, (u8 *)PartitionParams->PlAuth.AuthCertBuf); if (Status != XFSBL_SUCCESS) { return Status; } if (IsLastBlock == FALSE) { CurrentAcOffset = CurrentAcOffset + XFSBL_AUTH_CERT_MIN_SIZE; SrcAddress = SrcAddress + PartitionParams->PlAuth.BlockSize; } else { /* Completed last block of bitstream */ break; } } Xil_DCacheEnable(); #ifdef XFSBL_PS_DDR /* Restore reset values for the DMA registers used */ XFsbl_Out32(ADMA_CH0_ZDMA_CH_CTRL0, 0x00000080U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD2, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_DST_DSCR_WORD3, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD0, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD1, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD2, 0x00000000U); XFsbl_Out32(ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD3, 0x00000000U); #endif END: return Status; }
/** * This function does ECC Initialization of DDR memory * * @param none * * @return * - XFSBL_SUCCESS for successful ECC Initialization * - or ECC is not enabled for DDR * - errors as mentioned in xfsbl_error.h * *****************************************************************************/ u32 XFsbl_DdrEccInit(void) { u32 Status = XFSBL_SUCCESS; #if XPAR_PSU_DDRC_0_HAS_ECC u32 LengthBytes = XFSBL_PS_DDR_END_ADDRESS - XFSBL_PS_DDR_INIT_START_ADDRESS; u32 Length = 0; u32 DestAddr = XFSBL_PS_DDR_INIT_START_ADDRESS; u32 RegVal; XFsbl_Printf(DEBUG_GENERAL,"\n\rInitializing DDR ECC\n\r"); Xil_DCacheDisable(); while (LengthBytes > 0) { if (LengthBytes > GDMA_TRANSFER_MAX_LEN) { Length = GDMA_TRANSFER_MAX_LEN; } else { Length = LengthBytes; } /* Wait until the DMA is in idle state */ do { RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_STATUS); RegVal &= GDMA_CH0_ZDMA_CH_STATUS_STATE_MASK; } while ((RegVal != GDMA_CH0_ZDMA_CH_STATUS_STATE_DONE) && (RegVal != GDMA_CH0_ZDMA_CH_STATUS_STATE_ERR)); /* Enable Simple (Write Only) Mode */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_CTRL0); RegVal &= (GDMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_MASK | GDMA_CH0_ZDMA_CH_CTRL0_MODE_MASK); RegVal |= (GDMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_NORMAL | GDMA_CH0_ZDMA_CH_CTRL0_MODE_WR_ONLY); XFsbl_Out32(GDMA_CH0_ZDMA_CH_CTRL0, RegVal); /* Fill in the data to be written */ XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD0, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD1, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD2, XFSBL_ECC_INIT_VAL_WORD); XFsbl_Out32(GDMA_CH0_ZDMA_CH_WR_ONLY_WORD3, XFSBL_ECC_INIT_VAL_WORD); /* Write Destination Address */ XFsbl_Out32(GDMA_CH0_ZDMA_CH_DST_DSCR_WORD0, DestAddr); /* Size to be Transferred (for write-only mode, only dest is needed)*/ XFsbl_Out32(GDMA_CH0_ZDMA_CH_DST_DSCR_WORD2, Length); /* DMA Enable */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_CTRL2); RegVal |= GDMA_CH0_ZDMA_CH_CTRL2_EN_MASK; XFsbl_Out32(GDMA_CH0_ZDMA_CH_CTRL2, RegVal); /* Check the status of the transfer by polling on DMA Done */ do { RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_ISR); RegVal &= GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; } while (RegVal != GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Clear DMA status */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_ISR); RegVal |= GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK; XFsbl_Out32(GDMA_CH0_ZDMA_CH_ISR, GDMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK); /* Read the channel status for errors */ RegVal = XFsbl_In32(GDMA_CH0_ZDMA_CH_STATUS); if (RegVal == GDMA_CH0_ZDMA_CH_STATUS_STATE_ERR) { Status = XFSBL_ERROR_DDR_ECC_INIT; XFsbl_Printf(DEBUG_GENERAL,"XFSBL_ERROR_DDR_ECC_INIT\n\r"); Xil_DCacheEnable(); goto END; } LengthBytes -= Length; DestAddr += Length; } Xil_DCacheEnable(); END: #endif return Status; }