/************************************************************************************** Copyright (c) Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved. *************************************************************************************** $Id: $: Description: cifX Toolkit implementation of the netX50/51 boot functions Changes: Date Description ----------------------------------------------------------------------------------- 2021-08-31 IsNetX51or52ROM() sets now eChipType in device instance after checking 2018-09-24 moved hboot functions to separate module **************************************************************************************/ #include "cifXToolkit.h" #include "NetX_ROMLoader.h" #include "netx50_romloader_dpm.h" #include "netx51_romloader_dpm.h" #include "cifXErrors.h" #include "cifXEndianess.h" /*****************************************************************************/ /*! Structure describing a single HBOOT DPM mailbox */ /*****************************************************************************/ typedef struct HBOOT_MBX_DATA_Ttag { uint8_t bHskMask; /*!< Handshake bit to toggle for this mailbox */ uint32_t ulSize; /*!< Total size of mailbox */ void* pvData; /*!< Data area of mailbox */ volatile uint32_t* pulDataLen; /*!< Used size of mailbox */ } HBOOT_MBX_DATA_T; /*****************************************************************************/ /*! Structure describing HBOOT DPM */ /*****************************************************************************/ typedef struct HBOOT_DATA_Ttag { HBOOT_HSREGISTER_T* ptHsk; /*!< Handshake cell */ HBOOT_MBX_DATA_T tToNetXMailbox; /*!< Mailbox information Host-->netX */ HBOOT_MBX_DATA_T tToHostMailbox; /*!< Mailbox information netX-->Host */ } HBOOT_DATA_T; /*****************************************************************************/ /*! Detect a running netX51/52 ROMLoader via DPM * \param ptDevInstance Instance to reset * \return !=0 if netX51/52 has been detected */ /*****************************************************************************/ int IsNetX51or52ROM(PDEVICEINSTANCE ptDevInstance) { int iRet = 0; NETX51_DPM_CONFIG_AREA_T* ptDpmCfg = (NETX51_DPM_CONFIG_AREA_T*)ptDevInstance->pbDPM; if( (HWIF_READ8(ptDevInstance, ptDevInstance->pbDPM[NETX51_DETECT_OFFSET1]) == NETX51_DETECT_VALUE1) && (HWIF_READ8(ptDevInstance, ptDevInstance->pbDPM[NETX51_DETECT_OFFSET2]) == NETX51_DETECT_VALUE2) && (HWIF_READ32(ptDevInstance, ptDpmCfg->aulReserved1[0]) == 0) && (HWIF_READ32(ptDevInstance, ptDpmCfg->aulReserved1[1]) == 0) ) { /* We found a valid entry */ /* Check for netX51 or netX52 */ uint32_t ulDpmNetxVersion = (MSK_NX56_dpm_netx_version_valid | MSK_NX56_dpm_netx_version_chiptype) & HWIF_READ32(ptDevInstance, ptDpmCfg->ulDpmNetxVersion); if ( (MSK_NX56_dpm_netx_version_valid | ( 2 << SRT_NX56_dpm_netx_version_chiptype)) == ulDpmNetxVersion ) { /* This is a netX52 */ ptDevInstance->eChipType = eCHIP_TYPE_NETX52; } else { /* This is a netX51 */ ptDevInstance->eChipType = eCHIP_TYPE_NETX51; } iRet = 1; } return iRet; } /*****************************************************************************/ /*! Wait for bitstate in netX50/51 ROMloader (hboot) DPM * \param ptDevInstance Instance to download the bootloader to (needs a reset * before downloading) * \param ptHbootData Romloader boot data structure * \param ulBitMask Bitmask to check * \param bState Required state (HIL_FLAGS_EQUAL/NOT_EQUAL are supported * \param ulTimeout Timeout in ms to wait for packet * \return !=0 on success */ /*****************************************************************************/ static int hboot_waitforbitstate(PDEVICEINSTANCE ptDevInstance, HBOOT_DATA_T* ptHbootData, uint32_t ulBitMask, uint8_t bState, uint32_t ulTimeout) { int iRet = 0; int32_t lStartTime = 0; HBOOT_HSREGISTER_T* ptHsk = ptHbootData->ptHsk; uint8_t bActualState = 0; uint8_t bHostFlags = 0; UNREFERENCED_PARAMETER(ptDevInstance); bHostFlags = HWIF_READ8(ptDevInstance, ptHsk->t8Bit.bHostFlags); if((bHostFlags ^ HWIF_READ8(ptDevInstance, ptHsk->t8Bit.bNetXFlags)) & ulBitMask) bActualState = HIL_FLAGS_NOT_EQUAL; else bActualState = HIL_FLAGS_EQUAL; /* The desired state is already there, so just return true */ if(bActualState == bState) return 1; /* If no timeout is given, don't try to wait for the Bit change */ if(0 == ulTimeout) return 0; lStartTime = (int32_t)OS_GetMilliSecCounter(); /* Poll for desired bit state */ while(bActualState != bState) { uint32_t ulDiffTime = 0L; bHostFlags = HWIF_READ8(ptDevInstance, ptHsk->t8Bit.bHostFlags); if((bHostFlags ^ HWIF_READ8(ptDevInstance, ptHsk->t8Bit.bNetXFlags)) & ulBitMask) bActualState = HIL_FLAGS_NOT_EQUAL; else bActualState = HIL_FLAGS_EQUAL; /* Check for timeout */ ulDiffTime = OS_GetMilliSecCounter() - lStartTime; if ( ulDiffTime > ulTimeout) { break; } OS_Sleep(0); } if(bActualState == bState) iRet = 1; return iRet; } /*****************************************************************************/ /*! Send a packet to the netX50/51 romloader (hboot) * \param ptDevInstance Instance to download the bootloader to (needs a reset * before downloading) * \param ptHbootData Romloader boot data structure * \param pbData Send data buffer * \param ulDataLen Length of send data * \param ulTimeout Timeout in ms to wait for packet * \return CIFX_NO_ERROR on success */ /*****************************************************************************/ static int32_t hboot_send_packet(PDEVICEINSTANCE ptDevInstance, HBOOT_DATA_T* ptHbootData, uint8_t* pbData, uint32_t ulDataLen, uint32_t ulTimeout) { int32_t lRet = CIFX_NO_ERROR; HBOOT_HSREGISTER_T* ptHsk = ptHbootData->ptHsk; uint8_t bToNetXMask = ptHbootData->tToNetXMailbox.bHskMask; uint32_t ulMailboxSize = ptHbootData->tToNetXMailbox.ulSize; void* pvMailbox = ptHbootData->tToNetXMailbox.pvData; volatile uint32_t* pulMbxDataLen = ptHbootData->tToNetXMailbox.pulDataLen; if(ulDataLen > ulMailboxSize) return CIFX_INVALID_BUFFERSIZE; if(!hboot_waitforbitstate(ptDevInstance, ptHbootData, bToNetXMask, HIL_FLAGS_EQUAL, ulTimeout)) { /* The mailbox is busy */ lRet = CIFX_DEV_PUT_TIMEOUT; } else { uint8_t bHostFlags = 0; /* The mailbox is free */ HWIF_WRITEN(ptDevInstance, pvMailbox, pbData, ulDataLen); HWIF_WRITE32(ptDevInstance, pulMbxDataLen[0], HOST_TO_LE32(ulDataLen)); bHostFlags = HWIF_READ8(ptDevInstance, ptHsk->t8Bit.bHostFlags); HWIF_WRITE8(ptDevInstance, ptHsk->t8Bit.bHostFlags, (bHostFlags ^ bToNetXMask)); lRet = CIFX_NO_ERROR; } return lRet; } /*****************************************************************************/ /*! Get a packet from the netX50/51 romloader (hboot) * \param ptDevInstance Instance to download the bootloader to (needs a reset * before downloading) * \param ptHBootData Romloader boot data structure * \param pbResult Buffer for romloader error * \param ulTimeout Timeout in ms to wait for packet * \return CIFX_NO_ERROR on success */ /*****************************************************************************/ static int32_t hboot_get_packet(PDEVICEINSTANCE ptDevInstance, HBOOT_DATA_T* ptHBootData, uint8_t* pbResult, uint32_t ulTimeout) { int32_t lRet = CIFX_DEV_GET_NO_PACKET; if(hboot_waitforbitstate(ptDevInstance, ptHBootData, NETX50_DPM_TOHOSTMBX_MSK, HIL_FLAGS_NOT_EQUAL, ulTimeout)) { HBOOT_HSREGISTER_T* ptHskReg = ptHBootData->ptHsk; volatile uint8_t* pbMailbox = (volatile uint8_t*)ptHBootData->tToHostMailbox.pvData; volatile uint32_t* pulMbxDataLen = ptHBootData->tToHostMailbox.pulDataLen; uint8_t bToHostMask = ptHBootData->tToHostMailbox.bHskMask; uint8_t bHostFlags = 0; lRet = CIFX_NO_ERROR; if( LE32_TO_HOST(HWIF_READ32(ptDevInstance, pulMbxDataLen[0])) != 1) { lRet = CIFX_DRV_INIT_STATE_ERROR; } else { *pbResult = HWIF_READ8(ptDevInstance, pbMailbox[0]); } bHostFlags = HWIF_READ8(ptDevInstance, ptHskReg->t8Bit.bHostFlags); if((bHostFlags ^ HWIF_READ8(ptDevInstance, ptHskReg->t8Bit.bNetXFlags)) & bToHostMask) { HWIF_WRITE8(ptDevInstance, ptHskReg->t8Bit.bHostFlags, (bHostFlags ^ bToHostMask)); } } return lRet; } /*****************************************************************************/ /*! Exchanges a packet with the netX50/51 romloader (hboot) * \param ptDevInstance Instance to download the bootloader to (needs a reset * before downloading) * \param ptHBootData Romloader boot data structure * \param pbSendData Send data buffer * \param ulSendDataLen Send data length * \param pbResult Buffer for romloader error * \param ulTimeout Timeout in ms to wait for packet * \return CIFX_NO_ERROR on success */ /*****************************************************************************/ static int32_t hboot_transfer_packet(PDEVICEINSTANCE ptDevInstance, HBOOT_DATA_T* ptHBootData, uint8_t* pbSendData, uint32_t ulSendDataLen, uint8_t* pbResult, uint32_t ulTimeout) { int32_t lRet = CIFX_NO_ERROR; if(CIFX_NO_ERROR == (lRet = hboot_send_packet(ptDevInstance, ptHBootData, pbSendData, ulSendDataLen, ulTimeout))) { lRet = hboot_get_packet(ptDevInstance, ptHBootData, pbResult, ulTimeout); } return lRet; } /*****************************************************************************/ /*! Downloads and starts the bootloader on netX50/51 (hboot) * \param ptDevInstance Instance to download the bootloader to (needs a reset * before downloading) * \param pbFileData Pointer to bootloader file data * \param ulFileDataLen Length of bootloader file * \return CIFX_NO_ERROR on success */ /*****************************************************************************/ int32_t cifXStartBootloader_hboot(PDEVICEINSTANCE ptDevInstance, uint8_t* pbFileData, uint32_t ulFileDataLen) { int32_t lRet = CIFX_NO_ERROR; uint32_t ulCopyLen = 0; HBOOT_DATA_T tHBoot; OS_Memset(&tHBoot, 0, sizeof(tHBoot)); /* Check for chip type and initialize boot data structure */ if((eCHIP_TYPE_NETX51 == ptDevInstance->eChipType) || (eCHIP_TYPE_NETX52 == ptDevInstance->eChipType)) { PNETX51_ROMLOADER_DPM ptDpm = (PNETX51_ROMLOADER_DPM)ptDevInstance->pbDPM; tHBoot.ptHsk = (HBOOT_HSREGISTER_T*)&ptDpm->tHandshake.ulHandshakeFlag; tHBoot.tToHostMailbox.bHskMask = NETX51_DPM_TOHOSTMBX_MSK; tHBoot.tToHostMailbox.pulDataLen = &ptDpm->tHBootConfig.ulNetXToHostDataSize; tHBoot.tToHostMailbox.pvData = (void*)ptDpm->abNetxToHostData; tHBoot.tToHostMailbox.ulSize = sizeof(ptDpm->abNetxToHostData); tHBoot.tToNetXMailbox.bHskMask = NETX51_DPM_TONETXMBX_MSK; tHBoot.tToNetXMailbox.pulDataLen = &ptDpm->tHBootConfig.ulHostToNetxDataSize; tHBoot.tToNetXMailbox.pvData = (void*)ptDpm->abHostToNetxData; tHBoot.tToNetXMailbox.ulSize = sizeof(ptDpm->abHostToNetxData); if(g_ulTraceLevel & TRACE_LEVEL_DEBUG) { USER_Trace(ptDevInstance, TRACE_LEVEL_DEBUG, "Found netX51 ROMloader"); } } else { PNETX50_ROMLOADER_DPM ptDpm = (PNETX50_ROMLOADER_DPM)ptDevInstance->pbDPM; tHBoot.ptHsk = &ptDpm->atHandshakeRegs[NETX50_DPM_HANDSHAKE_OFFSET]; tHBoot.tToHostMailbox.bHskMask = NETX50_DPM_TOHOSTMBX_MSK; tHBoot.tToHostMailbox.pulDataLen = &ptDpm->ulNetxToHostDataSize; tHBoot.tToHostMailbox.pvData = (void*)ptDpm->abNetxToHostData; tHBoot.tToHostMailbox.ulSize = sizeof(ptDpm->abNetxToHostData); tHBoot.tToNetXMailbox.bHskMask = NETX50_DPM_TONETXMBX_MSK; tHBoot.tToNetXMailbox.pulDataLen = &ptDpm->ulHostToNetxDataSize; tHBoot.tToNetXMailbox.pvData = (void*)ptDpm->abHostToNetxData; tHBoot.tToNetXMailbox.ulSize = sizeof(ptDpm->abHostToNetxData); /* Read romloader version */ if(g_ulTraceLevel & TRACE_LEVEL_DEBUG) { uint32_t ulLayout = LE32_TO_HOST(HWIF_READ32(ptDevInstance, ptDpm->aulDpmHsRegs[NETX50_DPM_BLLAYOUT_OFFSET])); ulLayout = (ulLayout & MSK_NETX50_DPM_BLLAYOUT) >> SRT_NETX50_DPM_BLLAYOUT; USER_Trace(ptDevInstance, TRACE_LEVEL_DEBUG, "Found netX50 ROMloader, DPM layout type 0x%08X", ulLayout); } } ulCopyLen = tHBoot.tToNetXMailbox.ulSize; if(ulFileDataLen < sizeof(NETX_BOOTBLOCK_T)) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "Invalid Bootloader file. File must be larger than 64 Bytes. (Detected Size:%u)", ulFileDataLen); lRet = CIFX_FILE_TYPE_INVALID; } if(CIFX_NO_ERROR == lRet) { uint8_t bResult = 0; int fLastPacketReceived = 0; /* Send Bootblock to device */ if(CIFX_NO_ERROR != (lRet = hboot_transfer_packet(ptDevInstance, &tHBoot, pbFileData, sizeof(NETX_BOOTBLOCK_T), &bResult, CIFX_TO_SEND_PACKET))) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "Error transfering bootheader to netX50 Bootloader (lRet = 0x%08X)", lRet); } else if(0 != bResult) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "netX50 ROMloader rejected bootblock (bResult = %u)", bResult); lRet = CIFX_DRV_DOWNLOAD_FAILED; } else { /* Everything ok. start with rest of file */ pbFileData += (uint32_t)sizeof(NETX_BOOTBLOCK_T); ulFileDataLen -= (uint32_t)sizeof(NETX_BOOTBLOCK_T); } /* Download whole file and abort if something went wrong during download */ while( (ulFileDataLen > 0) && (lRet == CIFX_NO_ERROR) ) { /* Last fragment may be shorter */ if(ulFileDataLen < ulCopyLen) ulCopyLen = ulFileDataLen; /* Place message in mailbox and wait until message has been processed */ lRet = hboot_send_packet(ptDevInstance, &tHBoot, pbFileData, ulCopyLen, CIFX_TO_SEND_PACKET); if(CIFX_NO_ERROR != lRet) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "Error transferring data packet from/to netX50 Bootloader (lRet = 0x%08X)", lRet); } else if(CIFX_NO_ERROR == (hboot_get_packet(ptDevInstance, &tHBoot, &bResult, 0))) { /* Download is finished or has been aborted. Check will be done below */ fLastPacketReceived = 1; break; } pbFileData += ulCopyLen; ulFileDataLen -= ulCopyLen; } if(CIFX_NO_ERROR == lRet) { if(!fLastPacketReceived && (CIFX_NO_ERROR != (lRet = hboot_get_packet(ptDevInstance, &tHBoot, &bResult, CIFX_TO_SEND_PACKET))) ) { if(g_ulTraceLevel & TRACE_LEVEL_ERROR) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "Error getting final packet from netX50 ROM Loader. lRet=0x%08X", lRet); } } else if( 0 != bResult) { if(g_ulTraceLevel & TRACE_LEVEL_ERROR) { USER_Trace(ptDevInstance, TRACE_LEVEL_ERROR, "netX50 ROM Loader download error. bResult=%u", bResult); } lRet = CIFX_DRV_DOWNLOAD_FAILED; } } } return lRet; }