/** * This function perform the reset sequence to the given devcfg interface by * configuring the appropriate control bits in the devcfg specifc registers * the devcfg reset squence involves the following steps * Disable all the interuupts * Clear the status * Update relevant config registers with reset values * Disbale the looopback mode and pcap rate enable * * @param BaseAddress of the interface * * @return N/A * * @note * This function will not modify the slcr registers that are relavant for * devcfg controller ******************************************************************************/ void XDcfg_ResetHw(u32 BaseAddr) { u32 Regval = 0; /* Mask the interrupts */ XDcfg_WriteReg(BaseAddr, XDCFG_INT_MASK_OFFSET, XDCFG_IXR_ALL_MASK); /* Clear the interuupt status */ Regval = XDcfg_ReadReg(BaseAddr, XDCFG_INT_STS_OFFSET); XDcfg_WriteReg(BaseAddr, XDCFG_INT_STS_OFFSET, Regval); /* Clear the source address register */ XDcfg_WriteReg(BaseAddr, XDCFG_DMA_SRC_ADDR_OFFSET, 0x0); /* Clear the destination address register */ XDcfg_WriteReg(BaseAddr, XDCFG_DMA_DEST_ADDR_OFFSET, 0x0); /* Clear the source length register */ XDcfg_WriteReg(BaseAddr, XDCFG_DMA_SRC_LEN_OFFSET, 0x0); /* Clear the destination length register */ XDcfg_WriteReg(BaseAddr, XDCFG_DMA_DEST_LEN_OFFSET, 0x0); /* Clear the loopback enable bit */ Regval = XDcfg_ReadReg(BaseAddr, XDCFG_MCTRL_OFFSET); Regval = Regval & ~XDCFG_MCTRL_PCAP_LPBK_MASK; XDcfg_WriteReg(BaseAddr, XDCFG_MCTRL_OFFSET, Regval); /*Reset the configuration register to reset value */ XDcfg_WriteReg(BaseAddr, XDCFG_CFG_OFFSET, XDCFG_CONFIG_RESET_VALUE); /*Disable the PCAP rate enable bit */ Regval = XDcfg_ReadReg(BaseAddr, XDCFG_CTRL_OFFSET); Regval = Regval & ~XDCFG_CTRL_PCAP_RATE_EN_MASK; XDcfg_WriteReg(BaseAddr, XDCFG_CTRL_OFFSET, Regval); }
/** * The interrupt handler for the Device Config Interface. * * Events are signaled to upper layer for proper handling. * * * @param InstancePtr is a pointer to the XDcfg instance. * * @return None. * * @note None. * ****************************************************************************/ void XDcfg_InterruptHandler(XDcfg *InstancePtr) { u32 IntrStatusReg; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the Interrupt status register. */ IntrStatusReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_INT_STS_OFFSET); /* * Write the status back to clear the interrupts so that no * subsequent interrupts are missed while processing this interrupt. * This also does the DMA acknowledgment automatically. */ XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_INT_STS_OFFSET, IntrStatusReg); /* * Signal application that there are events to handle. */ InstancePtr->StatusHandler(InstancePtr->CallBackRef, IntrStatusReg); }
/** * * The function reads the contents of the Configuration Register with the * given value. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return A 32-bit value representing the contents of the Config * Register. * Use the XDCFG_CFG_*_MASK constants defined in xdevcfg_hw.h to * interpret the returned value. * * @note None. * *****************************************************************************/ u32 XDcfg_GetConfigRegister(XDcfg *InstancePtr) { /* * Assert the arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); return XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_CFG_OFFSET); }
/** * * The function reads the contents of the Miscellaneous Control Register. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return 32 Bit boot software ID. * * @note This register is locked for write once the system enters * usermode. Hence API to reading the register only is provided. * *****************************************************************************/ u32 XDcfg_GetMiscControlRegister(XDcfg *InstancePtr) { /* * Assert the arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the Miscellaneous Control Register and return the value. */ return XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); }
/** * * The function reads the contents of the Software ID Register. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return 32 Bit boot software ID. * * @note This register is locked for write once the system enters * usermode. Hence API for reading the register only is provided. * *****************************************************************************/ u32 XDcfg_GetSoftwareIdRegister(XDcfg *InstancePtr) { /* * Assert the arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read the Software ID Register and return the value. */ return XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_SW_ID_OFFSET); }
/** * * This function returns the interrupt status read from Interrupt Status * Register. Use the XDCFG_INT_* constants defined in xdevcfg_hw.h * to interpret the returned value. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return A 32-bit value representing the contents of the Interrupt * Status register. * * @note None. * *****************************************************************************/ u32 XDcfg_IntrGetStatus(XDcfg *InstancePtr) { /* * Assert the arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Return the value read from the Interrupt Status register. */ return XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_INT_STS_OFFSET); }
/** * * The function sets the bit mask for the feature in Miscellaneous Control * Register. * * @param InstancePtr is a pointer to the XDcfg instance. * @param Mask is the bit-mask of the feature to be set. * * @return None. * * @note None * *****************************************************************************/ void XDcfg_SetMiscControlRegister(XDcfg *InstancePtr, u32 Mask) { u32 RegData; /* * Assert the arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); RegData = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET, (RegData | Mask)); }
/** * * The functions disables the PCAP interface by clearing the PCAP mode bit in * the control register. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return None. * * @note None. * *****************************************************************************/ void XDcfg_DisablePCAP(XDcfg *InstancePtr) { u32 CtrlReg; /* * Assert the arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (CtrlReg & ( ~XDCFG_CTRL_PCAP_MODE_MASK))); }
/** * * The function Clears the specified bit positions of the Control Register. * * @param InstancePtr is a pointer to the XDcfg instance. * @param Mask is the 32 bit value which holds the bit positions to be cleared. * * @return None. * * @note None. * *****************************************************************************/ void XDcfg_ClearControlRegister(XDcfg *InstancePtr, u32 Mask) { u32 CtrlReg; /* * Assert the arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (CtrlReg & ~Mask)); }
static XDcfg *XDcfg_Initialize(u16 DeviceId) { u32 CtrlReg; u32 Status; XDcfg *Instance = malloc(sizeof *Instance); XDcfg_Config *Config = XDcfg_LookupConfig(DeviceId); Status = XDcfg_CfgInitialize(Instance, Config, Config->BaseAddr); if(Status != XST_SUCCESS){ print("Device configuration initialisation failed\n\r"); exit(0); } // Disable PCAP interface for partial reconfiguration XDcfg_DisablePCAP(Instance); CtrlReg = XDcfg_ReadReg(Instance->Config.BaseAddr,XDCFG_CTRL_OFFSET); XDcfg_WriteReg(Instance->Config.BaseAddr, XDCFG_CTRL_OFFSET,(CtrlReg & XDCFG_CTRL_ICAP_PR_MASK)); return Instance; }
/** * * This function checks if DMA command queue is full. * * @param InstancePtr is a pointer to the XDcfg instance. * * @return XST_SUCCESS is the DMA is busy * XST_FAILURE if the DMA is idle * * @note The DMA queue has a depth of two. * ****************************************************************************/ u32 XDcfg_IsDmaBusy(XDcfg *InstancePtr) { u32 RegData; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* Read the PCAP status register for DMA status */ RegData = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_STATUS_OFFSET); if ((RegData & XDCFG_STATUS_DMA_CMD_Q_F_MASK) == XDCFG_STATUS_DMA_CMD_Q_F_MASK){ return XST_SUCCESS; } return XST_FAILURE; }
/** * * This function enables the specified interrupts in the device. * * @param InstancePtr is a pointer to the XDcfg instance. * @param Mask is the bit-mask of the interrupts to be enabled. * Bit positions of 1 will be enabled. Bit positions of 0 will * keep the previous setting. This mask is formed by OR'ing * XDCFG_INT_* bits defined in xdevcfg_hw.h. * * @return None. * * @note None. * *****************************************************************************/ void XDcfg_IntrEnable(XDcfg *InstancePtr, u32 Mask) { u32 RegValue; /* * Assert the arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Enable the specified interrupts in the Interrupt Mask Register. */ RegValue = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_INT_MASK_OFFSET); RegValue &= ~(Mask & XDCFG_IXR_ALL_MASK); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_INT_MASK_OFFSET, RegValue); }
/** * * This function Implements the DMA Read Command. This command is used to * transfer the image data from FPGA to the external memory. * * @param InstancePtr is a pointer to the XDcfg instance. * @param SourcePtr contains a pointer to the source memory where the data * is to be transferred from. * @param SrcWordLength is the number of words (32 bit) to be transferred * for the source transfer. * @param DestPtr contains a pointer to the destination memory * where the data is to be transferred to. * @param DestWordLength is the number of words (32 bit) to be transferred * for the Destination transfer. * * @return - XST_INVALID_PARAM if source address/length is invalid. * - XST_SUCCESS if DMA transfer initiated properly. * * @note None. * ****************************************************************************/ static u32 XDcfg_PcapReadback(XDcfg *InstancePtr, u32 SourcePtr, u32 SrcWordLength, u32 DestPtr, u32 DestWordLength) { u32 IntrReg; /* * Send READ Frame command to FPGA */ XDcfg_InitiateDma(InstancePtr, SourcePtr, XDCFG_DMA_INVALID_ADDRESS, SrcWordLength, 0); /* * Store the enabled interrupts to enable before the actual read * transfer is initiated and Disable all the interrupts temporarily. */ IntrReg = XDcfg_IntrGetEnabled(InstancePtr); XDcfg_IntrDisable(InstancePtr, XDCFG_IXR_ALL_MASK); /* * Wait till you get the DMA done for the read command sent */ while ((XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_INT_STS_OFFSET) & XDCFG_IXR_D_P_DONE_MASK) == XDCFG_IXR_D_P_DONE_MASK); /* * Enable the previously stored Interrupts . */ XDcfg_IntrEnable(InstancePtr, IntrReg); /* * Initiate the DMA write command. */ XDcfg_InitiateDma(InstancePtr, XDCFG_DMA_INVALID_ADDRESS, (u32)DestPtr, 0, DestWordLength); return XST_SUCCESS; }
/** * * This function programs the Fabric for use. * * @param None * * @return None * - XST_SUCCESS if the Fabric initialization is successful * - XST_FAILURE if the Fabric initialization fails * @note None * ****************************************************************************/ void FabricInit(void) { u32 PcapReg; u32 PcapCtrlRegVal; u32 StatusReg; /* * Set Level Shifters DT618760 - PS to PL enabling */ Xil_Out32(PS_LVL_SHFTR_EN, LVL_PS_PL); fsbl_printf(DEBUG_INFO,"Level Shifter Value = 0x%x \r\n", Xil_In32(PS_LVL_SHFTR_EN)); /* * Get DEVCFG controller settings */ PcapReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET); /* * Setting PCFG_PROG_B signal to high */ XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK)); /* * Check for AES source key */ PcapCtrlRegVal = XDcfg_GetControlRegister(DcfgInstPtr); if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { /* * 5msec delay */ usleep(5000); } /* * Setting PCFG_PROG_B signal to low */ XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (PcapReg & ~XDCFG_CTRL_PCFG_PROG_B_MASK)); /* * Check for AES source key */ if (PcapCtrlRegVal & XDCFG_CTRL_PCFG_AES_FUSE_MASK) { /* * 5msec delay */ usleep(5000); } /* * Polling the PCAP_INIT status for Reset */ while(XDcfg_GetStatusRegister(DcfgInstPtr) & XDCFG_STATUS_PCFG_INIT_MASK); /* * Setting PCFG_PROG_B signal to high */ XDcfg_WriteReg(DcfgInstPtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (PcapReg | XDCFG_CTRL_PCFG_PROG_B_MASK)); /* * Polling the PCAP_INIT status for Set */ while(!(XDcfg_GetStatusRegister(DcfgInstPtr) & XDCFG_STATUS_PCFG_INIT_MASK)); /* * Get Device configuration status */ StatusReg = XDcfg_GetStatusRegister(DcfgInstPtr); fsbl_printf(DEBUG_INFO,"Devcfg Status register = 0x%x \r\n",StatusReg); fsbl_printf(DEBUG_INFO,"PCAP:Fabric is Initialized done\r\n"); }
/** * * This function starts the DMA transfer. This function only starts the * operation and returns before the operation may be completed. * If the interrupt is enabled, an interrupt will be generated when the * operation is completed, otherwise it is necessary to poll the Status register * to determine when it is completed. It is the responsibility of the caller to * determine when the operation is completed by handling the generated interrupt * or polling the Status Register. * * @param InstancePtr is a pointer to the XDcfg instance. * @param SourcePtr contains a pointer to the source memory where the data * is to be transferred from. * @param SrcWordLength is the number of words (32 bit) to be transferred * for the source transfer. * @param DestPtr contains a pointer to the destination memory * where the data is to be transferred to. * @param DestWordLength is the number of words (32 bit) to be transferred * for the Destination transfer. * @param TransferType contains the type of PCAP transfer being requested. * The definitions can be found in the xdevcfg.h file. * @return * - XST_SUCCESS.if DMA transfer initiated successfully * - XST_DEVICE_BUSY if DMA is busy * - XST_INVALID_PARAM if invalid Source / Destination address * is sent or an invalid Source / Destination length is * sent * * @note It is the responsibility of the caller to ensure that the cache * is flushed and invalidated both before the DMA operation is * started and after the DMA operation completes if the memory * pointed to is cached. The caller must also ensure that the * pointers contain physical address rather than a virtual address * if address translation is being used. * * The 2 LSBs of the SourcePtr (Source)/ DestPtr (Destination) * address when equal to 2’b01 indicates the last DMA command of * an overall transfer. * *****************************************************************************/ u32 XDcfg_Transfer(XDcfg *InstancePtr, void *SourcePtr, u32 SrcWordLength, void *DestPtr, u32 DestWordLength, u32 TransferType) { u32 CtrlReg; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); if (XDcfg_IsDmaBusy(InstancePtr) == XST_SUCCESS) { return XST_DEVICE_BUSY; } /* * Check whether the fabric is in initialized state */ if ((XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_STATUS_OFFSET) & XDCFG_STATUS_PCFG_INIT_MASK) == 0) { /* * We don't need to check PCFG_INIT to be high for * non-encrypted loopback transfers. */ if (TransferType != XDCFG_CONCURRENT_NONSEC_READ_WRITE) { return XST_FAILURE; } } if ((TransferType == XDCFG_SECURE_PCAP_WRITE) || (TransferType == XDCFG_NON_SECURE_PCAP_WRITE)) { /* Check for valid source pointer and length */ if ((!SourcePtr) || (SrcWordLength == 0)) { return XST_INVALID_PARAM; } /* Clear internal PCAP loopback */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET, (CtrlReg & ~(XDCFG_MCTRL_PCAP_LPBK_MASK))); if (TransferType == XDCFG_NON_SECURE_PCAP_WRITE) { /* * Clear QUARTER_PCAP_RATE_EN bit * so that the PCAP data is transmitted every clock */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (CtrlReg & ~XDCFG_CTRL_PCAP_RATE_EN_MASK)); } if (TransferType == XDCFG_SECURE_PCAP_WRITE) { /* * AES engine handles only 8 bit data every clock cycle. * Hence, Encrypted PCAP data which is 32 bit data can * only be sent in every 4 clock cycles. Set the control * register QUARTER_PCAP_RATE_EN bit to achieve this * operation. */ XDcfg_SetControlRegister(InstancePtr, XDCFG_CTRL_PCAP_RATE_EN_MASK); } XDcfg_InitiateDma(InstancePtr, (u32)SourcePtr, (u32)DestPtr, SrcWordLength, DestWordLength); } if (TransferType == XDCFG_PCAP_READBACK) { if ((!DestPtr) || (DestWordLength == 0)) { return XST_INVALID_PARAM; } /* Clear internal PCAP loopback */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET, (CtrlReg & ~(XDCFG_MCTRL_PCAP_LPBK_MASK))); /* * For PCAP readback of FPGA configuration register or memory, * the read command is first sent (written) to the FPGA fabric * which responds by returning the required read data. Read data * from the FPGA is captured if pcap_radata_v is active.A DMA * read transfer is required to obtain the readback command, * which is then sent to the FPGA, followed by a DMA write * transfer to support this mode of operation. */ return XDcfg_PcapReadback(InstancePtr, (u32)SourcePtr, SrcWordLength, (u32)DestPtr, DestWordLength); } if ((TransferType == XDCFG_CONCURRENT_SECURE_READ_WRITE) || (TransferType == XDCFG_CONCURRENT_NONSEC_READ_WRITE)) { if ((!SourcePtr) || (SrcWordLength == 0) || (!DestPtr) || (DestWordLength == 0)) { return XST_INVALID_PARAM; } if (TransferType == XDCFG_CONCURRENT_NONSEC_READ_WRITE) { /* Enable internal PCAP loopback */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET, (CtrlReg | XDCFG_MCTRL_PCAP_LPBK_MASK)); /* * Clear QUARTER_PCAP_RATE_EN bit * so that the PCAP data is transmitted every clock */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_CTRL_OFFSET, (CtrlReg & ~XDCFG_CTRL_PCAP_RATE_EN_MASK)); } if (TransferType == XDCFG_CONCURRENT_SECURE_READ_WRITE) { /* Clear internal PCAP loopback */ CtrlReg = XDcfg_ReadReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET); XDcfg_WriteReg(InstancePtr->Config.BaseAddr, XDCFG_MCTRL_OFFSET, (CtrlReg & ~(XDCFG_MCTRL_PCAP_LPBK_MASK))); /* * Set the QUARTER_PCAP_RATE_EN bit * so that the PCAP data is transmitted every 4 clock * cycles, this is required for encrypted data. */ XDcfg_SetControlRegister(InstancePtr, XDCFG_CTRL_PCAP_RATE_EN_MASK); } XDcfg_InitiateDma(InstancePtr, (u32)SourcePtr, (u32)DestPtr, SrcWordLength, DestWordLength); } return XST_SUCCESS; }
/** * * This function * * @param * * @return * * * @note None * ****************************************************************************/ u32 LoadBootImage(void) { u32 RebootStatusRegister = 0; u32 MultiBootReg = 0; u32 ImageStartAddress = 0; u32 PartitionNum; u32 PartitionDataLength; u32 PartitionImageLength; u32 PartitionTotalSize; u32 PartitionExecAddr; u32 PartitionAttr; u32 ExecAddress = 0; u32 PartitionLoadAddr; u32 PartitionStartAddr; u32 PartitionChecksumOffset; u8 ExecAddrFlag = 0 ; u32 Status; PartHeader *HeaderPtr; u32 EfuseStatusRegValue; #ifdef RSA_SUPPORT u32 HeaderSize; #endif /* * Resetting the Flags */ BitstreamFlag = 0; ApplicationFlag = 0; RebootStatusRegister = Xil_In32(REBOOT_STATUS_REG); fsbl_printf(DEBUG_INFO, "Reboot status register: 0x%08x\r\n",RebootStatusRegister); if (Silicon_Version == SILICON_VERSION_1) { /* * Clear out fallback mask from previous run * We start from the first partition again */ if ((RebootStatusRegister & FSBL_FAIL_MASK) == FSBL_FAIL_MASK) { fsbl_printf(DEBUG_INFO, "Reboot status shows previous run falls back\r\n"); RebootStatusRegister &= ~(FSBL_FAIL_MASK); Xil_Out32(REBOOT_STATUS_REG, RebootStatusRegister); } /* * Read the image start address */ ImageStartAddress = *(u32 *)BASEADDR_HOLDER; } else { /* * read the multiboot register */ MultiBootReg = XDcfg_ReadReg(DcfgInstPtr->Config.BaseAddr, XDCFG_MULTIBOOT_ADDR_OFFSET); fsbl_printf(DEBUG_INFO,"Multiboot Register: 0x%08x\r\n",MultiBootReg); /* * Compute the image start address */ ImageStartAddress = (MultiBootReg & PCAP_MBOOT_REG_REBOOT_OFFSET_MASK) * GOLDEN_IMAGE_OFFSET; } fsbl_printf(DEBUG_INFO,"Image Start Address: 0x%08x\r\n",ImageStartAddress); /* * Get partitions header information */ Status = GetPartitionHeaderInfo(ImageStartAddress); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL, "Partition Header Load Failed\r\n"); OutputStatus(GET_HEADER_INFO_FAIL); FsblFallback(); } /* * RSA is not implemented in 1.0 and 2.0 * silicon */ if ((Silicon_Version != SILICON_VERSION_1) && (Silicon_Version != SILICON_VERSION_2)) { /* * Read Efuse Status Register */ EfuseStatusRegValue = Xil_In32(EFUSE_STATUS_REG); if (EfuseStatusRegValue & EFUSE_STATUS_RSA_ENABLE_MASK) { fsbl_printf(DEBUG_GENERAL,"RSA enabled for Chip\r\n"); #ifdef RSA_SUPPORT /* * Set the Ppk */ SetPpk(); /* * Read partition header with signature */ Status = GetImageHeaderAndSignature(ImageStartAddress, (u32 *)DDR_TEMP_START_ADDR); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL, "Read Partition Header signature Failed\r\n"); OutputStatus(GET_HEADER_INFO_FAIL); FsblFallback(); } HeaderSize=TOTAL_HEADER_SIZE+RSA_SIGNATURE_SIZE; Status = AuthenticatePartition((u8 *)DDR_TEMP_START_ADDR, HeaderSize); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL, "Partition Header signature Failed\r\n"); OutputStatus(GET_HEADER_INFO_FAIL); FsblFallback(); } #else /* * In case user not enabled RSA authentication feature */ fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n"); OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL); FsblFallback(); #endif } } #ifdef MMC_SUPPORT /* * In case of MMC support * boot image preset in MMC will not have FSBL partition */ PartitionNum = 0; #else /* * First partition header was ignored by FSBL * As it contain FSBL partition information */ PartitionNum = 1; #endif while (PartitionNum < PartitionCount) { fsbl_printf(DEBUG_INFO, "Partition Number: %d\r\n", PartitionNum); HeaderPtr = &PartitionHeader[PartitionNum]; /* * Print partition header information */ HeaderDump(HeaderPtr); /* * Validate partition header */ Status = ValidateHeader(HeaderPtr); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL, "INVALID_HEADER_FAIL\r\n"); OutputStatus(INVALID_HEADER_FAIL); FsblFallback(); } /* * Load partition header information in to local variables */ PartitionDataLength = HeaderPtr->DataWordLen; PartitionImageLength = HeaderPtr->ImageWordLen; PartitionExecAddr = HeaderPtr->ExecAddr; PartitionAttr = HeaderPtr->PartitionAttr; PartitionLoadAddr = HeaderPtr->LoadAddr; PartitionChecksumOffset = HeaderPtr->CheckSumOffset; PartitionStartAddr = HeaderPtr->PartitionStart; PartitionTotalSize = HeaderPtr->PartitionWordLen; /* * Partition owner should be FSBL to validate the partition */ if ((PartitionAttr & ATTRIBUTE_PARTITION_OWNER_MASK) != ATTRIBUTE_PARTITION_OWNER_FSBL) { /* * if FSBL is not the owner of partition, * skip this partition, continue with next partition */ fsbl_printf(DEBUG_INFO, "Skipping partition %0x\r\n", PartitionNum); /* * Increment partition number */ PartitionNum++; continue; } if (PartitionAttr & ATTRIBUTE_PL_IMAGE_MASK) { fsbl_printf(DEBUG_INFO, "Bitstream\r\n"); PLPartitionFlag = 1; PSPartitionFlag = 0; BitstreamFlag = 1; if (ApplicationFlag == 1) { #ifdef STDOUT_BASEADDRESS xil_printf("\r\nFSBL Warning !!!" "Bitstream not loaded into PL\r\n"); xil_printf("Partition order invalid\r\n"); #endif break; } } if (PartitionAttr & ATTRIBUTE_PS_IMAGE_MASK) { fsbl_printf(DEBUG_INFO, "Application\r\n"); PSPartitionFlag = 1; PLPartitionFlag = 0; ApplicationFlag = 1; } /* * Encrypted partition will have different value * for Image length and data length */ if (PartitionDataLength != PartitionImageLength) { fsbl_printf(DEBUG_INFO, "Encrypted\r\n"); EncryptedPartitionFlag = 1; } else { EncryptedPartitionFlag = 0; } /* * Check for partition checksum check */ if (PartitionAttr & ATTRIBUTE_CHECKSUM_TYPE_MASK) { PartitionChecksumFlag = 1; } else { PartitionChecksumFlag = 0; } /* * RSA signature check */ if (PartitionAttr & ATTRIBUTE_RSA_PRESENT_MASK) { fsbl_printf(DEBUG_INFO, "RSA Signed\r\n"); SignedPartitionFlag = 1; } else { SignedPartitionFlag = 0; } /* * Load address check * Loop will break when PS load address zero and partition is * un-signed or un-encrypted */ if ((PSPartitionFlag == 1) && (PartitionLoadAddr < DDR_START_ADDR)) { if ((PartitionLoadAddr == 0) && (!((SignedPartitionFlag == 1) || (EncryptedPartitionFlag == 1)))) { break; } else { fsbl_printf(DEBUG_GENERAL, "INVALID_LOAD_ADDRESS_FAIL\r\n"); OutputStatus(INVALID_LOAD_ADDRESS_FAIL); FsblFallback(); } } if (PSPartitionFlag && (PartitionLoadAddr > DDR_END_ADDR)) { fsbl_printf(DEBUG_GENERAL, "INVALID_LOAD_ADDRESS_FAIL\r\n"); OutputStatus(INVALID_LOAD_ADDRESS_FAIL); FsblFallback(); } /* * Load execution address of first PS partition */ if (PSPartitionFlag && (!ExecAddrFlag)) { ExecAddrFlag++; ExecAddress = PartitionExecAddr; } /* * FSBL user hook call before bitstream download */ if (PLPartitionFlag) { Status = FsblHookBeforeBitstreamDload(); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"FSBL_BEFORE_BSTREAM_HOOK_FAIL\r\n"); OutputStatus(FSBL_BEFORE_BSTREAM_HOOK_FAIL); FsblFallback(); } } /* * Move partitions from boot device */ Status = PartitionMove(ImageStartAddress, HeaderPtr); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"PARTITION_MOVE_FAIL\r\n"); OutputStatus(PARTITION_MOVE_FAIL); FsblFallback(); } if ((SignedPartitionFlag) || (PartitionChecksumFlag)) { if(PLPartitionFlag) { /* * PL partition loaded in to DDR temporary address * for authentication and checksum verification */ PartitionStartAddr = DDR_TEMP_START_ADDR; } else { PartitionStartAddr = PartitionLoadAddr; } if (PartitionChecksumFlag) { /* * Validate the partition data with checksum */ Status = ValidateParition(PartitionStartAddr, (PartitionTotalSize << WORD_LENGTH_SHIFT), ImageStartAddress + (PartitionChecksumOffset << WORD_LENGTH_SHIFT)); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"PARTITION_CHECKSUM_FAIL\r\n"); OutputStatus(PARTITION_CHECKSUM_FAIL); FsblFallback(); } fsbl_printf(DEBUG_INFO, "Partition Validation Done\r\n"); } /* * Authentication Partition */ if (SignedPartitionFlag == 1 ) { #ifdef RSA_SUPPORT Xil_DCacheEnable(); Status = AuthenticatePartition((u8*)PartitionStartAddr, (PartitionTotalSize << WORD_LENGTH_SHIFT)); if (Status != XST_SUCCESS) { Xil_DCacheFlush(); Xil_DCacheDisable(); fsbl_printf(DEBUG_GENERAL,"AUTHENTICATION_FAIL\r\n"); OutputStatus(AUTHENTICATION_FAIL); FsblFallback(); } fsbl_printf(DEBUG_INFO,"Authentication Done\r\n"); Xil_DCacheFlush(); Xil_DCacheDisable(); #else /* * In case user not enabled RSA authentication feature */ fsbl_printf(DEBUG_GENERAL,"RSA_SUPPORT_NOT_ENABLED_FAIL\r\n"); OutputStatus(RSA_SUPPORT_NOT_ENABLED_FAIL); FsblFallback(); #endif } /* * Decrypt PS partition */ if (EncryptedPartitionFlag && PSPartitionFlag) { Status = DecryptPartition(PartitionStartAddr, PartitionDataLength, PartitionImageLength); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"DECRYPTION_FAIL\r\n"); OutputStatus(DECRYPTION_FAIL); FsblFallback(); } } /* * Load Signed PL partition in Fabric */ if (PLPartitionFlag) { Status = PcapLoadPartition((u32*)PartitionStartAddr, (u32*)PartitionLoadAddr, PartitionImageLength, PartitionDataLength, EncryptedPartitionFlag); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"BITSTREAM_DOWNLOAD_FAIL\r\n"); OutputStatus(BITSTREAM_DOWNLOAD_FAIL); FsblFallback(); } } } /* * FSBL user hook call after bitstream download */ if (PLPartitionFlag) { Status = FsblHookAfterBitstreamDload(); if (Status != XST_SUCCESS) { fsbl_printf(DEBUG_GENERAL,"FSBL_AFTER_BSTREAM_HOOK_FAIL\r\n"); OutputStatus(FSBL_AFTER_BSTREAM_HOOK_FAIL); FsblFallback(); } } /* * Increment partition number */ PartitionNum++; } return ExecAddress; }