/* * Copyright 2021-2023 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "fwd_hdll.h" #include "phNxpConfig.h" #include "phNxpLog.h" #include "phNxpUciHal_fwd_utils.h" #include "phNxpUciHal_utils.h" #include "phTmlUwb_spi.h" #define MAX_FRAME_LEN 4200 static uint8_t is_fw_download_log_enabled = 0x00; static phFWD_Status_t openFwBinFile(phUwbFWImageContext_t *pfwImageCtx); static phFWD_Status_t openFwSoFile(phUwbFWImageContext_t *pfwImageCtx); static phFWD_Status_t phNxpUciHal_fw_recovery(phUwbFWImageContext_t *pfwImageCtx); char default_fw_path[FILEPATH_MAXLEN] = "/vendor/firmware/uwb/"; const char *default_dev_fw_bin = "libsr200t_fw.bin"; const char *default_dev_fw_so = "libsr200t_fw.so"; const char *default_so_file_extn = ".so"; extern uint32_t timeoutTimerId; static bool isHdllReadTmeoutExpired = false; static bool bSkipEdlCheck = false; static bool glcRotation = false; phUwbFWImageContext_t fwImageCtx; /******************************************************************************* ** ** Function : phGenericSendAndRecv ** ** Description : This function sends the HDLL commands to HeliosX chip over SPI using phHdll_PutApdu() and gets the response using phHdll_GetApdu(). ** ** Parameters : payload - HDLL command to be sent len - HDLL command length readbuff - HDLL command response buffer rsp_buf_len - HDLL command rsponse buffer length ** ** Returns : phFWD_Status_t : 0 - success 1 - failure ** ** *******************************************************************************/ phFWD_Status_t phGenericSendAndRecv(uint8_t *payload, uint16_t len, uint8_t *read_buff, uint16_t *rsp_buf_len) { phFWD_Status_t ret = FW_DNLD_FAILURE; if (FW_DNLD_SUCCESS != (ret = phHdll_PutApdu((uint8_t *)&payload[0], len))) { return ret; } if (FW_DNLD_SUCCESS != (ret = phHdll_GetApdu((uint8_t *)&read_buff[0], HDLL_READ_BUFF_SIZE, rsp_buf_len))) { return ret; } return ret; } /******************************************************************************* ** ** Function : print_getInfoRsp ** ** Description : This function prints the HDLL GetInfo command's response ** ** Parameters : getInfoRsp - Struct which has the GetInfo response details. ** ** Returns : None ** ** *******************************************************************************/ void print_getInfoRsp(phHDLLGetInfo_t *getInfoRsp) { uint8_t i = 0, offset = 0; char buff[HDLL_READ_BUFF_SIZE] = {0}; if (NULL == getInfoRsp) { return; } NXPLOG_FWDNLD_D("=====================GET_INFO =======================\n"); NXPLOG_FWDNLD_D("Boot Status: 0x%02X\n", getInfoRsp->boot_status); NXPLOG_FWDNLD_D("Session Control: 0x%02X\n", getInfoRsp->session_control); NXPLOG_FWDNLD_D("Session Type: 0x%02X\n", getInfoRsp->session_type); NXPLOG_FWDNLD_D("ROM Version: 0x%02X\n", getInfoRsp->rom_version); NXPLOG_FWDNLD_D("AT Page Status: 0x%02X\n", getInfoRsp->AT_page_status); NXPLOG_FWDNLD_D("Chip Version: Major.Minor: %02X.%02X\n", getInfoRsp->chip_major_ver, getInfoRsp->chip_minor_ver); NXPLOG_FWDNLD_D("FW Version: Major.Minor: %02X.%02X\n", getInfoRsp->fw_major_ver, getInfoRsp->fw_minor_ver); for (i = 0; i != 8; i += 2) { // 4bytes sprintf(&buff[i], "%02X", getInfoRsp->chip_variant[offset++]); } buff[i] = '\0'; NXPLOG_FWDNLD_D("Chip Variant: 0x%s\n", buff); NXPLOG_FWDNLD_D("Device Lifecycle: 0x%X\n", getInfoRsp->device_life_cycle); for (i = 0, offset = 0; i != 32; i += 2) { // 16bytes sprintf(&buff[i], "%02X", getInfoRsp->chip_id[offset++]); } buff[i] = '\0'; NXPLOG_FWDNLD_D("Chip ID: 0x%s\n", buff); for (i = 0, offset = 0; i != 8; i += 2) { // 4bytes sprintf(&buff[i], "%02X", getInfoRsp->chip_id_crc[offset++]); } buff[i] = '\0'; NXPLOG_FWDNLD_D("Chip ID CRC:0x%s\n", buff); NXPLOG_FWDNLD_D("=====================================================\n"); } /******************************************************************************* ** ** Function : process_getInfo_rsp ** ** Description : This function processes the HDLL GetInfo command's response ** ** Parameters : payload - Struct in which the processed info will be kept ** ** Returns : On failure - NULL On success - Pointer to the phHDLLGetInfo_t struct ** ** *******************************************************************************/ phHDLLGetInfo_t *process_getInfo_rsp(uint8_t *payload) { uint8_t offset = 0; phHDLLGetInfo_t *getInfoRsp = NULL; uint8_t device_lc_mode[4] = {0}; getInfoRsp = (phHDLLGetInfo_t *)malloc(sizeof(phHDLLGetInfo_t)); if (NULL == getInfoRsp) { return NULL; } memset(getInfoRsp, 0, sizeof(phHDLLGetInfo_t)); getInfoRsp->boot_status = payload[offset++]; getInfoRsp->session_control = payload[offset++]; getInfoRsp->session_type = payload[offset++]; getInfoRsp->rom_version = (eUWBD_Rom_Version_t)payload[offset++]; getInfoRsp->AT_page_status = (eUWBD_AT_Page_status_t)payload[offset++]; offset += 2; // padding bytes getInfoRsp->chip_major_ver = payload[offset++]; getInfoRsp->chip_minor_ver = payload[offset++]; getInfoRsp->fw_major_ver = payload[offset++]; getInfoRsp->fw_minor_ver = payload[offset++]; memcpy(getInfoRsp->chip_variant, payload + offset, sizeof(uint8_t) * 4); offset += 4; memcpy(device_lc_mode, payload + offset, sizeof(uint8_t) * 4); getInfoRsp->device_life_cycle = (eUWBD_LC_mode_t)(device_lc_mode[0] | (device_lc_mode[1] << 8) | (device_lc_mode[2] << 16) | (device_lc_mode[3] << 24)); offset += 4; memcpy(getInfoRsp->chip_id, payload + offset, sizeof(uint8_t) * 16); offset += 16; memcpy(getInfoRsp->chip_id_crc, payload + offset, sizeof(uint8_t) * 4); return getInfoRsp; } /******************************************************************************* ** ** Function : getFwImageCtx ** ** Description : This function use to get the FW image context ** ** Parameters : pfwImageCtx -> pointer to fw image context ** ** Returns : On failure - returns FW_DNLD_FAILURE - or FW_DNLD_FILE_NOT_FOUND if FW file not present in the MW. On success - returns FW_DNLD_SUCCESS. ** ** *******************************************************************************/ phFWD_Status_t getFwImageCtx(phUwbFWImageContext_t *pfwImageCtx) { phFWD_Status_t status = FW_DNLD_SUCCESS; char *configured_fw_name = NULL; const uint16_t fw_file_max_len = FILENAME_MAXLEN; const char *pDefaultFwFileName = NULL; char* ret = NULL; configured_fw_name = (char *)malloc(fw_file_max_len * sizeof(char)); int maxSrcLen = (FILEPATH_MAXLEN - strlen(pfwImageCtx->default_fw_path)) - 1; if (configured_fw_name == NULL) { NXPLOG_FWDNLD_E("malloc of configured_fw_name failed "); return FW_DNLD_FAILURE; } /* Default FW download configset to bin file */ pDefaultFwFileName = default_dev_fw_bin; if (!NxpConfig_GetStr(NAME_NXP_UWB_FW_FILENAME, configured_fw_name, fw_file_max_len)) { NXPLOG_FWDNLD_D("Invalid Dev Fw name keeping the default name: %s", pDefaultFwFileName); strncat(pfwImageCtx->default_fw_path, pDefaultFwFileName, maxSrcLen); } else { NXPLOG_FWDNLD_D("configured_fw_name : %s", configured_fw_name); strncat(pfwImageCtx->default_fw_path, configured_fw_name, maxSrcLen); } NXPLOG_FWDNLD_D("fw file path : %s", pfwImageCtx->default_fw_path); // Search for so extension in filename ret = strstr(configured_fw_name, default_so_file_extn); if(ret) { pfwImageCtx->fw_dnld_config = SO_FILE_BASED_FW_DOWNLOAD; /* Get Fw Context from so file */ status = openFwSoFile(pfwImageCtx); } else { /* Get Fw Context from bin file */ status = openFwBinFile(pfwImageCtx); } if (configured_fw_name != NULL) { free(configured_fw_name); } memset(pfwImageCtx->default_fw_path, '\0', sizeof(char) * FILEPATH_MAXLEN); strcpy(pfwImageCtx->default_fw_path, "/vendor/firmware/uwb/"); return status; } /******************************************************************************* ** ** Function : printManifestInfo ** ** Description : This function is use to get UWB Manifest info ** ** Parameters : pfwImageCtx -> pointer to fw image context ** ** Returns : On failure - returns FW_DNLD_FAILURE - or FW_DNLD_FILE_NOT_FOUND if FW file not present in the MW. On success - returns FW_DNLD_SUCCESS. ** ** *******************************************************************************/ void printManifest_info(UWBManifest_t *fwLibManifest) { if(fwLibManifest == NULL) { return; } NXPLOG_FWDNLD_D("================= FW Lib Manifest ====================\n"); NXPLOG_FWDNLD_D("UWB manifest version = %x\n",fwLibManifest->layout_version); NXPLOG_FWDNLD_D("UWB manifest creation year = %d\n",fwLibManifest->creation_date_yy); NXPLOG_FWDNLD_D("UWB manifest creation month = %d\n",fwLibManifest->creation_date_month); NXPLOG_FWDNLD_D("UWB manifest creation day = %d\n",fwLibManifest->creation_date_day); NXPLOG_FWDNLD_D("UWB manifest creation hour = %d\n",fwLibManifest->creation_date_hour); NXPLOG_FWDNLD_D("UWB manifest creation minutes = %d\n",fwLibManifest->creation_date_minutes); NXPLOG_FWDNLD_D("UWB manifest creation seconds = %d\n",fwLibManifest->creation_date_seconds); NXPLOG_FWDNLD_D("UWB manifest count = %d\n",fwLibManifest->countMWCESFW); return; } /******************************************************************************* ** ** Function : openFwSoFile ** ** Description : This function loads the FW shared library context if the FW file exists otherwise returns failure. ** ** Parameters : pfwImageCtx -> pointer to fw image context ** ** Returns : On failure - returns FW_DNLD_FAILURE - or FW_DNLD_FILE_NOT_FOUND if FW file not present in the MW. On success - returns FW_DNLD_SUCCESS. ** ** *******************************************************************************/ static phFWD_Status_t openFwSoFile(phUwbFWImageContext_t *pfwImageCtx) { void *flibptr = NULL; UWBManifest_t *currentFwLib = NULL; pfwImageCtx->gFwLib = NULL; phFWD_Status_t status = FW_DNLD_SUCCESS; NXPLOG_FWDNLD_D("%s:%d enter", __func__,__LINE__); pfwImageCtx->gFwLib = dlopen(pfwImageCtx->default_fw_path, RTLD_LAZY); if (pfwImageCtx->gFwLib == NULL) { // Apparently, the library could not be opened NXPLOG_FWDNLD_E("%s: Error! opening FW file %s\n", __func__, pfwImageCtx->default_fw_path); status = FW_DNLD_FILE_NOT_FOUND; goto cleanup; } flibptr = dlsym(pfwImageCtx->gFwLib, "gUWBManifest"); if (!flibptr) { NXPLOG_FWDNLD_E("%s: Could not get function pointer\n", __func__); status = FW_DNLD_FAILURE; goto cleanup; } currentFwLib = (UWBManifest_t *)flibptr; if (currentFwLib == NULL) { NXPLOG_FWDNLD_E("%s:%d UwbManifest is null exiting.....", __func__, __LINE__); status = FW_DNLD_FAILURE; goto cleanup; } printManifest_info(currentFwLib); // read the FW bytes into buffer if (pfwImageCtx->deviceInfo->rom_version == VER_A1V1) { if(currentFwLib->mwCESFW[MWCESFW_A1V1_RECOVERY_FW_OFFSET] == NULL || currentFwLib->mwCESFW[MWCESFW_A1V1_FW_OFFSET] == NULL) { NXPLOG_FWDNLD_E("%s:%d UwbManifest mwCESFW is null exiting.....", __func__, __LINE__); status = FW_DNLD_FAILURE; goto cleanup; } if(pfwImageCtx->deviceInfo->AT_page_status == STATUS_PAGE_ERROR) { pfwImageCtx->fwRecovery = true; pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V1_RECOVERY_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V1_RECOVERY_FW_OFFSET]->pCESFW; } else if((pfwImageCtx->deviceInfo->device_life_cycle == CUSTOMER_MODE) && glcRotation == true) { if(currentFwLib->mwCESFW[MWCESFW_A1V1_LC_FW_OFFSET] == NULL ) { NXPLOG_FWDNLD_E("%s:%d LC FW does not exist.....", __func__, __LINE__); status = FW_DNLD_FAILURE; goto cleanup; } else { pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V1_LC_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V1_LC_FW_OFFSET]->pCESFW; } }else { pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V1_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V1_FW_OFFSET]->pCESFW; } } else if (pfwImageCtx->deviceInfo->rom_version == VER_A1V2) { if(currentFwLib->mwCESFW[MWCESFW_A1V2_RECOVERY_FW_OFFSET] == NULL || currentFwLib->mwCESFW[MWCESFW_A1V2_FW_OFFSET] == NULL) { NXPLOG_FWDNLD_E("%s:%d UwbManifest mwCESFW is null exiting.....", __func__, __LINE__); status = FW_DNLD_FAILURE; goto cleanup; } if(pfwImageCtx->deviceInfo->AT_page_status == STATUS_PAGE_ERROR) { pfwImageCtx->fwRecovery = true; pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V2_RECOVERY_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V2_RECOVERY_FW_OFFSET]->pCESFW; } else if((pfwImageCtx->deviceInfo->device_life_cycle == CUSTOMER_MODE) && glcRotation == true) { if(currentFwLib->mwCESFW[MWCESFW_A1V2_LC_FW_OFFSET] == NULL ) { NXPLOG_FWDNLD_E("%s:%d LC FW does not exist.....", __func__, __LINE__); status = FW_DNLD_FAILURE; goto cleanup; } else { pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V2_LC_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V2_LC_FW_OFFSET]->pCESFW; } } else { pfwImageCtx->fwImgSize = currentFwLib->mwCESFW[MWCESFW_A1V2_FW_OFFSET]->lenCESFW; pfwImageCtx->fwImage = currentFwLib->mwCESFW[MWCESFW_A1V2_FW_OFFSET]->pCESFW; } } if ((!(pfwImageCtx->fwImgSize)) || (NULL == pfwImageCtx->fwImage)) { NXPLOG_FWDNLD_E("%s: Error! File %s is empty\n", __func__, pfwImageCtx->default_fw_path); status = FW_DNLD_FAILURE; goto cleanup; } NXPLOG_FWDNLD_E("exiting %s fwImgSize %d" , __func__, pfwImageCtx->fwImgSize); return status; cleanup: if (pfwImageCtx->gFwLib != NULL) { dlclose(pfwImageCtx->gFwLib); pfwImageCtx->gFwLib = NULL; } return status; } /******************************************************************************* ** ** Function : openFwBinFile ** ** Description : This function copies the entire Bin FW file content into a buffer if the FW file exists otherwise returns failure. ** ** Parameters : pfwImageCtx -> pointer to fw image context ** ** Returns : On failure - returns FW_DNLD_FAILURE - or FW_DNLD_FILE_NOT_FOUND if FW file not present in the MW. On success - returns FW_DNLD_SUCCESS. ** ** *******************************************************************************/ static phFWD_Status_t openFwBinFile(phUwbFWImageContext_t *pfwImageCtx) { phFWD_Status_t status = FW_DNLD_SUCCESS; long int file_size = 0; size_t ret_size = 0; FILE *fptr = NULL; NXPLOG_FWDNLD_D("%s:%d enter", __func__,__LINE__); // open FW binary file if ((fptr = fopen(pfwImageCtx->default_fw_path, "rb")) == NULL) { NXPLOG_FWDNLD_E("%s: Error! opening FW file %s\n", __func__, pfwImageCtx->default_fw_path); status = FW_DNLD_FILE_NOT_FOUND; goto exit; } // find the FW binary file size fseek(fptr, 0L, SEEK_END); file_size = ftell(fptr); if (!file_size || (-1L == file_size)) { NXPLOG_FWDNLD_E("%s: Error! File %s is empty\n", __func__, pfwImageCtx->default_fw_path); status = FW_DNLD_FAILURE; goto exit; } else { pfwImageCtx->fwImgSize = file_size; } // read the FW bytes into buffer pfwImageCtx->fwImage = (uint8_t *)malloc(sizeof(uint8_t) * pfwImageCtx->fwImgSize); if (NULL == pfwImageCtx->fwImage) { status = FW_DNLD_FAILURE; NXPLOG_FWDNLD_E("%s: Error in allocating memory\n", __func__); goto exit; } rewind(fptr); ret_size = fread(pfwImageCtx->fwImage, sizeof(uint8_t), pfwImageCtx->fwImgSize, fptr); if (ret_size != pfwImageCtx->fwImgSize) { if (feof(fptr)) { NXPLOG_FWDNLD_E("%s: Error reading file %s, unexpected end of file\n", __func__, pfwImageCtx->default_fw_path); } else if (ferror(fptr)) { NXPLOG_FWDNLD_E("%s: Error reading file %s\n", __func__, pfwImageCtx->default_fw_path); } status = FW_DNLD_FAILURE; goto exit; } exit: if (NULL != fptr) { fclose(fptr); } return status; } /******************************************************************************* ** ** Function : check_fw_update_required ** ** Description : This function checks whether FW update is required or not based on FW version from MW binary and FW version present in the HeliosX chip. ** ** Parameters : getInfoRsp - Struct which has the GetInfo response details. ** ** Returns : FW_DNLD_FAILURE - If any un expected failure FW_DNLD_NOT_REQUIRED - FW update not required FW_DNLD_REQUIRED - FW update required FW_DNLD_FILE_NOT_FOUND - if the FW bin file is unable to open or not present ** ** *******************************************************************************/ phFWD_Status_t check_fw_update_required(phHDLLGetInfo_t *getInfoRsp) { uint32_t next_frame_first_byte_index = 0; uint32_t index = 0; uint8_t mw_fw_major_ver = 0; uint8_t mw_fw_minor_ver = 0; uint32_t frame_payload_length = 0; uint32_t frame_length = 0; unsigned long num = 0; phFWD_Status_t status = FW_DNLD_FAILURE; fwImageCtx.deviceInfo = getInfoRsp; fwImageCtx.fw_dnld_config = BIN_FILE_BASED_FW_DOWNLOAD; fwImageCtx.fw_flash_config = FLASH_UPPER_VER_UPDATE; fwImageCtx.fwRecovery = false; strcpy(fwImageCtx.default_fw_path, default_fw_path); status = getFwImageCtx(&fwImageCtx); if (status != FW_DNLD_SUCCESS) { return status; } if (NxpConfig_GetNum(NAME_NXP_UWB_FLASH_CONFIG, &num, sizeof(num))) { fwImageCtx.fw_flash_config = (uint8_t)num; NXPLOG_FWDNLD_D("NAME_NXP_UWB_FLASH_CONFIG: 0x%02x\n", fwImageCtx.fw_flash_config); if (!(fwImageCtx.fw_flash_config == FLASH_UPPER_VER_UPDATE || fwImageCtx.fw_flash_config == FLASH_DIFFERENT_VER_UPDATE || fwImageCtx.fw_flash_config == FLASH_FORCE_UPDATE)) { fwImageCtx.fw_flash_config = FLASH_UPPER_VER_UPDATE; } } else { NXPLOG_FWDNLD_D("NAME_NXP_UWB_FLASH_CONFIG: failed 0x%02x\n", fwImageCtx.fw_flash_config); } frame_payload_length = (fwImageCtx.fwImage[next_frame_first_byte_index] << 8) + (fwImageCtx.fwImage[next_frame_first_byte_index + 1]); frame_length = frame_payload_length + HDLL_HEADER_LEN + HDLL_FOOTER_LEN; // get the index of first_write_cmd_payload next_frame_first_byte_index = next_frame_first_byte_index + frame_length; index = next_frame_first_byte_index; mw_fw_major_ver = fwImageCtx.fwImage[index + MW_MAJOR_FW_VER_OFFSET]; mw_fw_minor_ver = fwImageCtx.fwImage[index + MW_MINOR_FW_VER_OFFSET]; NXPLOG_FWDNLD_D("mw_fw_ver: %02X.%02X chip_fw_ver: %02X.%02X\n", mw_fw_major_ver, mw_fw_minor_ver, getInfoRsp->fw_major_ver, getInfoRsp->fw_minor_ver); if(getInfoRsp->session_control == SESSION_CONTROL_OPEN){ NXPLOG_FWDNLD_D("FW Update required as session control is open \n"); status = FW_DNLD_REQUIRED; } else { switch (fwImageCtx.fw_flash_config) { case FLASH_UPPER_VER_UPDATE: { if (mw_fw_major_ver > getInfoRsp->fw_major_ver) { NXPLOG_FWDNLD_D("FLASH_UPPER_VER_UPDATE:FW Update required\n"); status = FW_DNLD_REQUIRED; } else if (mw_fw_major_ver == getInfoRsp->fw_major_ver) { if (mw_fw_minor_ver > getInfoRsp->fw_minor_ver) { NXPLOG_FWDNLD_D("FLASH_UPPER_VER_UPDATE:FW Update required\n"); status = FW_DNLD_REQUIRED; } else { NXPLOG_FWDNLD_E( "FLASH_UPPER_VER_UPDATE:FW lower Minor version is not supported\n"); status = FW_DNLD_NOT_REQUIRED; } } else { NXPLOG_FWDNLD_E( "FLASH_UPPER_VER_UPDATE:FW lower Major version is not supported\n"); status = FW_DNLD_NOT_REQUIRED; } } break; case FLASH_FORCE_UPDATE: { if (mw_fw_major_ver < getInfoRsp->fw_major_ver) { NXPLOG_FWDNLD_E( "FLASH_FORCE_UPDATE:FW lower Major version is not supported\n"); status = FW_DNLD_NOT_REQUIRED; } else { NXPLOG_FWDNLD_D("FLASH_FORCE_UPDATE:FW Update required\n"); status = FW_DNLD_REQUIRED; } } break; case FLASH_DIFFERENT_VER_UPDATE: { if (mw_fw_major_ver > getInfoRsp->fw_major_ver) { NXPLOG_FWDNLD_D("FLASH_DIFFERENT_VER_UPDATE:FW Update required\n"); status = FW_DNLD_REQUIRED; } else if(mw_fw_major_ver == getInfoRsp->fw_major_ver) { if(mw_fw_minor_ver == getInfoRsp->fw_minor_ver) { NXPLOG_FWDNLD_E( "FLASH_DIFFERENT_VER_UPDATE:Same Minor FW version update is not supported\n"); status = FW_DNLD_NOT_REQUIRED; } else { NXPLOG_FWDNLD_E( "FLASH_DIFFERENT_VER_UPDATE:FW Update required\n"); status = FW_DNLD_REQUIRED; } } else { NXPLOG_FWDNLD_D("FLASH_DIFFERENT_VER_UPDATE:lower Major FW version update is not supported\n"); status = FW_DNLD_NOT_REQUIRED;; } } break; } } return status; } /******************************************************************************* ** ** Function : handleGetInfoRsp ** ** Description : This function handles the GetInfo response that is received from the HeliosX chip. ** ** Parameters : hdll_payload - HDLL response buffer ** ** Returns : FW_DNLD_FAILURE - If any un expected failure FW_DNLD_NOT_REQUIRED - FW update not required FW_DNLD_REQUIRED - FW update required FW_DNLD_FILE_NOT_FOUND - if the FW bin file is unable to open or not present ** ** *******************************************************************************/ phFWD_Status_t handleGetInfoRsp(uint8_t *hdll_payload) { phFWD_Status_t ret = FW_DNLD_FAILURE; phHDLLGetInfo_t *getInfoRsp = NULL; getInfoRsp = process_getInfo_rsp(hdll_payload); if (NULL == getInfoRsp) { return ret; } print_getInfoRsp(getInfoRsp); ret = check_fw_update_required(getInfoRsp); if (NULL != getInfoRsp) { free(getInfoRsp); } return ret; } /******************************************************************************* ** ** Function : printHDLLRspStatus ** ** Description : This function prints the HDLL response status string based on the given status code ** Parameters : status - status code ** ** Returns : None ** ** *******************************************************************************/ void printHDLLRspStatus(uint8_t status) { switch (status) { case GENERIC_SUCCESS: NXPLOG_FWDNLD_D("Received status: GENERIC_SUCCESS"); break; case ACKNOWLEDGE: NXPLOG_FWDNLD_D("Received status: ACKNOWLEDGE"); break; case READY: NXPLOG_FWDNLD_D("Received status: READY"); break; case GENERIC_ERROR: NXPLOG_FWDNLD_D("Received status: GENERIC_ERROR"); break; case MEMORY_ERROR: NXPLOG_FWDNLD_D("Received status: MEMORY_ERROR"); break; case TIMEOUT_ERROR: NXPLOG_FWDNLD_D("Received status: TIMEOUT_ERROR"); break; case CRC_ERROR: NXPLOG_FWDNLD_D("Received status: CRC_ERROR"); break; case INVALID_ERROR: NXPLOG_FWDNLD_D("Received status: INVALID_ERROR"); break; case INVALID_LENGTH_ERROR: NXPLOG_FWDNLD_D("Received status: INVALID_LENGTH_ERROR"); break; case INVALID_ADDRESS_ERROR: NXPLOG_FWDNLD_D("Received status: INVALID_ADDRESS_ERROR"); break; case ECC_SIGNATURE_ERROR: NXPLOG_FWDNLD_D("Received status: ECC_SIGNATURE_ERROR"); break; case SHA384_HASH_ERROR: NXPLOG_FWDNLD_D("Received status: SHA384_HASH_ERROR"); break; case LIFECYCLE_VALIDITY_ERROR: NXPLOG_FWDNLD_D("Received status: LIFECYCLE_VALIDITY_ERROR"); break; case CHIP_ID_ERROR: NXPLOG_FWDNLD_D("Received status: CHIP_ID_ERROR"); break; case CHIP_VERSION_ERROR: NXPLOG_FWDNLD_D("Received status: CHIP_VERSION_ERROR"); break; case CERTIFICATE_VERSION_ERROR: NXPLOG_FWDNLD_D("Received status: CERTIFICATE_VERSION_ERROR"); break; case FIRMWARE_VERSION_ERROR: NXPLOG_FWDNLD_D("Received status: FIRMWARE_VERSION_ERROR"); break; case SRAM_DOWNLOAD_ALLOW_ERROR: NXPLOG_FWDNLD_D("Received status: SRAM_DOWNLOAD_ALLOW_ERROR"); break; case KEY_DERIVATION_ERROR: NXPLOG_FWDNLD_D("Received status: KEY_DERIVATION_ERROR"); break; case ENCRYPTED_PAYLOAD_DECRYPTION_ERROR: NXPLOG_FWDNLD_D("Received status: ENCRYPTED_PAYLOAD_DECRYPTION_ERROR"); break; case INVALID_ENCRYPTED_PAYLOAD_ERROR: NXPLOG_FWDNLD_D("Received status: INVALID_ENCRYPTED_PAYLOAD_ERROR"); break; case PROTECTED_CACHE_LOAD_ERROR: NXPLOG_FWDNLD_D("Received status: PROTECTED_CACHE_LOAD_ERROR"); break; case PROTECTED_CACHE_DEPLOY_ERROR: NXPLOG_FWDNLD_D("Received status: PROTECTED_CACHE_DEPLOY_ERROR"); break; case LIFECYCLE_UPDATE_ERROR: NXPLOG_FWDNLD_D("Received status: LIFECYCLE_UPDATE_ERROR"); break; case FLASH_BLANK_PAGE_ERROR: NXPLOG_FWDNLD_D("Received status: FLASH_BLANK_PAGE_ERROR"); break; case FLASH_CHECK_MARGIN_ERROR: NXPLOG_FWDNLD_D("Received status: FLASH_CHECK_MARGIN_ERROR"); break; default: break; }; } /******************************************************************************* ** ** Function : process_hdll_response ** ** Description : This function processes the HDLL response ** Parameters : hdllCmdRsp - HDLL command response structure which has the received response info as well as the expected response info. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ /* * HDLL Response: * <-------HDLL Header--->|<------------------HDLL payload---------------------> * <-------HDLL (2bytes)->|<-----HCP (2bytes)------->|<-Application--> <--CRC--> * <31 30> <29> <28 -16> |<15 -14><13 - 8> <7 - 0> |<2 bytes> * <--R--> |< Type >|<1 byte> * */ phFWD_Status_t process_hdll_response(phHDLLCmdRsp_t *hdllCmdRsp) { uint8_t hdll_msg_type = 0; uint8_t hdll_rsp_status = 0; uint16_t hdll_packet_len = 0; uint8_t hdll_group = 0; uint8_t hdll_operation = 0; uint8_t *hdll_payload = NULL; uint16_t hdll_payload_len = 0; phFWD_Status_t ret = FW_DNLD_FAILURE; if (hdllCmdRsp == NULL || hdllCmdRsp->rsp_buf == NULL) { NXPLOG_FWDNLD_E("%s HDLL response buffer is NULL\n", __func__); return ret; } if (hdllCmdRsp->rsp_buf_len < HDLL_MIN_RSP_LEN) { NXPLOG_FWDNLD_E( "%s Error! HDLL response buffer length is %d, expected min %d bytes\n", __func__, hdllCmdRsp->rsp_buf_len, HDLL_MIN_RSP_LEN); return ret; } // parse hdll frame hdll_packet_len = (uint16_t)(hdllCmdRsp->rsp_buf[0] << 8) | (hdllCmdRsp->rsp_buf[HDLL_LEN_OFFSET]); hdll_packet_len &= HDLL_PKT_LEN_BITMASK; NXPLOG_FWDNLD_D("Received RSP packet len :0x%04X\n", hdll_packet_len); if (hdll_packet_len == 0) { NXPLOG_FWDNLD_D("Error in hdll response.. hdll_packet_len = 0\n"); return ret; } hdll_msg_type = hdllCmdRsp->rsp_buf[HDLL_TYPE_OFFSET] >> HCP_GROUP_LEN; hdll_group = (hdllCmdRsp->rsp_buf[HDLL_GROUP_OFFSET] & HDLL_RSP_GROUP_BIT_MASK); hdll_operation = hdllCmdRsp->rsp_buf[HDLL_OPERATION_OFFSET]; hdll_rsp_status = hdllCmdRsp->rsp_buf[HDLL_RSP_STATUS_OFFSET]; NXPLOG_FWDNLD_D("Received RSP msg type :0x%02X\n", hdll_msg_type); NXPLOG_FWDNLD_D("Received RSP group operation :0x%02X%02X\n", hdll_group, hdll_operation); NXPLOG_FWDNLD_D("Received RSP status code :0x%02X\n", hdll_rsp_status); printHDLLRspStatus(hdll_rsp_status); hdll_payload_len = hdllCmdRsp->rsp_buf_len - (HDLL_RSP_PAYLOAD_OFFSET + HDLL_CRC_LEN); NXPLOG_FWDNLD_D("hdll payload len = 0x%02x" , hdll_payload_len); if (hdll_payload_len > 0) { hdll_payload = (uint8_t *)malloc( sizeof(uint8_t) * (hdll_payload_len)); if (NULL == hdll_payload) { return ret; } memcpy(hdll_payload, &hdllCmdRsp->rsp_buf[HDLL_RSP_PAYLOAD_OFFSET], hdll_payload_len); } // validate the response if (hdllCmdRsp->status != hdll_rsp_status) { NXPLOG_FWDNLD_D("Error! expected response status code is 0x%02X but " "received 0x%02X\n", hdllCmdRsp->status, hdll_rsp_status); ret = FW_DNLD_FAILURE; } else if (hdllCmdRsp->type != hdll_msg_type) { NXPLOG_FWDNLD_D( "Error! expected HDLL type code is 0x%02X but received 0x%02X\n", hdllCmdRsp->type, hdll_msg_type); ret = FW_DNLD_FAILURE; } else if ((hdllCmdRsp->group != hdll_group) || (hdllCmdRsp->operation != hdll_operation)) { NXPLOG_FWDNLD_D("Error! expected response operation code is 0x%02X%02X but " "received 0x%02X%02X \n", hdllCmdRsp->group, hdllCmdRsp->operation, hdll_group, hdll_operation); ret = FW_DNLD_FAILURE; } else { ret = FW_DNLD_SUCCESS; } if (ret == FW_DNLD_FAILURE){ goto exit; } // Handle the response according to the operation switch (hdll_group) { case HCP_OPERATION_GROUP_PROTOCOL: { switch (hdll_operation) { case PROTOCOL_GROUP_OP_CODE_HDLL: { NXPLOG_FWDNLD_D("Received PROTOCOL_GROUP_HDLL_OP_CODE\n"); } break; case PROTOCOL_GROUP_OP_CODE_HCP: { NXPLOG_FWDNLD_D("Received PROTOCOL_GROUP_HCP_OP_CODE\n"); } break; case PROTOCOL_GROUP_OP_CODE_EDL: { NXPLOG_FWDNLD_D("Received PROTOCOL_GROUP_EDL_OP_CODE\n"); } break; } } break; case HCP_OPERATION_GROUP_GENERIC: { switch (hdll_operation) { case GENERIC_GROUP_OP_CODE_RESET: { NXPLOG_FWDNLD_D("Received OP_GENERIC_RESET\n"); // Generic reset cmd will have the rsp only in case of error. // How to handle the situation. } break; case GENERIC_GROUP_OP_CODE_GETINFO: { NXPLOG_FWDNLD_D("Received OP_GENERIC_GET_INFO\n"); if (hdll_payload != NULL) { ret = handleGetInfoRsp(hdll_payload); } } break; } } break; case HCP_OPERATION_GROUP_EDL: { switch (hdll_operation) { case EDL_DOWNLOAD_CERTIFICATE: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_CERTIFICATE\n"); } break; case EDL_DOWNLOAD_FLASH_WRITE_FIRST: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_FLASH_WRITE_FIRST\n"); } break; case EDL_DOWNLOAD_FLASH_WRITE: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_FLASH_WRITE\n"); } break; case EDL_DOWNLOAD_FLASH_WRITE_LAST: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_FLASH_WRITE_LAST\n"); } break; case EDL_DOWNLOAD_SRAM_WRITE_FIRST: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_SRAM_WRITE_FIRST\n"); } break; case EDL_DOWNLOAD_SRAM_WRITE: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_SRAM_WRITE\n"); } break; case EDL_DOWNLOAD_SRAM_WRITE_LAST: { NXPLOG_FWDNLD_D("Received OP_EDL_DOWNLOAD_SRAM_WRITE_LAST\n"); } break; case EDL_LIFECYCLE_CERTIFICATE: { NXPLOG_FWDNLD_D("Received OP_EDL_LIFECYCLE_CERTIFICATE\n"); } break; case EDL_LIFECYCLE_WRITE_FIRST: { NXPLOG_FWDNLD_D("Received OP_EDL_LIFECYCLE_WRITE_FIRST\n"); } break; case EDL_LIFECYCLE_WRITE_LAST: { NXPLOG_FWDNLD_D("Received OP_EDL_LIFECYCLE_WRITE_LAST\n"); } break; case EDL_PATCH_SRAM_WRITE: { NXPLOG_FWDNLD_D("Received OP_EDL_PATCH_SRAM_WRITE\n"); } break; case EDL_PATCH_SRAM_WRITE_LAST: { NXPLOG_FWDNLD_D("Received OP_EDL_PATCH_SRAM_WRITE_LAST\n"); } break; case EDL_PATCH_FLASH_WRITE: { NXPLOG_FWDNLD_D("Received OP_EDL_PATCH_FLASH_WRITE\n"); } break; } } break; default: break; } exit: if (hdll_payload != NULL) { free(hdll_payload); } return ret; } /******************************************************************************* ** ** Function : sendEdlDownloadCertificateCmd ** ** Description : This function frames the EdlDownloadCertificateCmd which needs to be sent as part of FW download sequence. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlDownloadCertificateCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving OP_EDL_DOWNLOAD_CERTIFICATE " "cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_DOWNLOAD_CERTIFICATE; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlFlashWriteFirstCmd ** ** Description : This function frames the EdlFlashWriteFirstCmd which needs to be sent as part of FW download sequence. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlFlashWriteFirstCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving " "OP_EDL_DOWNLOAD_FLASH_WRITE_FIRST cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_DOWNLOAD_FLASH_WRITE_FIRST; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlFlashWriteCmd ** ** Description : This function frames the sendEdlFlashWriteCmd which will have the actual FW chunk. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlFlashWriteCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving OP_EDL_DOWNLOAD_FLASH_WRITE " "cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_DOWNLOAD_FLASH_WRITE; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlFlashWriteLastCmd ** ** Description : This function frames the EdlFlashWriteLastCmd which needs to be sent as part of FW download sequence. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlFlashWriteLastCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving " "OP_EDL_DOWNLOAD_FLASH_WRITE_LAST cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_DOWNLOAD_FLASH_WRITE_LAST; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlLifecycleCertificateCmd ** ** Description : This function frames the EdlLifecycleCertificateCmd which needs to be sent as part of Lifecycle update. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlLifecycleCertificateCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving " "EDL_LIFECYCLE_CERTIFICATE cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_LIFECYCLE_CERTIFICATE; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlLifecycleWriteFirstCmd ** ** Description : This function frames the EdlLifecycleWriteFirstCmd which needs to be sent as part of Lifecycle update. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlLifecycleWriteFirstCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving " "EDL_LIFECYCLE_WRITE_FIRST cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_LIFECYCLE_WRITE_FIRST; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlLifecycleWriteLastCmd ** ** Description : This function frames the EdlLifecycleWriteLastCmd which needs to be sent as part of Lifecycle update. ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlLifecycleWriteLastCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving " "EDL_LIFECYCLE_WRITE_LAST cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_LIFECYCLE_WRITE_LAST; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : sendEdlPatchFlashWriteCmd ** ** Description : This function frames the sendEdlPatchlFlashWriteCmd which will send the EDL Patch Flash Write cmd ** ** Parameters : payload - HDLL command buffer len - command buffer length rsp_buf - response buffer that will be received from the HeliosX chip. ** ** Returns : FW_DNLD_FAILURE - If any undesired response received FW_DNLD_SUCCESS - On proper response ** ** *******************************************************************************/ phFWD_Status_t sendEdlPatchFlashWriteCmd(uint8_t *payload, uint16_t len, uint8_t *rsp_buf) { uint16_t rsp_buf_len = 0x0; phFWD_Status_t ret = FW_DNLD_SUCCESS; phHDLLCmdRsp_t *hdllCmdRsp = NULL; ret = phGenericSendAndRecv(payload, len, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving OP_EDL_PATCH_FLASH_WRITE " "cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_EDL; hdllCmdRsp->operation = EDL_PATCH_FLASH_WRITE; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : phHal_Host_CalcCrc16 ** ** Description : This function calculates the HDLL command's CRC ** ** Parameters : p - HDLL command buffer dwLength - command buffer length ** ** Returns : the calculated CRC value ** ** *******************************************************************************/ static uint16_t phHal_Host_CalcCrc16(uint8_t *p, uint32_t dwLength) { uint32_t i; uint16_t crc_new; uint16_t crc = 0xffffU; for (i = 0; i < dwLength; i++) { crc_new = (uint8_t)(crc >> 8) | (crc << 8); crc_new ^= p[i]; crc_new ^= (uint8_t)(crc_new & 0xff) >> 4; crc_new ^= crc_new << 12; crc_new ^= (crc_new & 0xff) << 5; crc = crc_new; } return crc; } /******************************************************************************* ** ** Function : phBuildHdllCmd ** ** Description : This function frames the final HDLL command (HDLL header + HDLL payload + CRC) by framing HDLL payload and HDLL frame using 2 different APIs. ** ** Parameters : hdllCmd - HDLL command structure which has the information to build the corresponding HDLL command. ** ** Returns : NULL - on failure HDLL command buffer - On success ** ** *******************************************************************************/ /* * HDLL Command: * <--------HDLL Header---->|<------------------HDLL payload-------------------> * <--------HDLL (2bytes)-->|<-----HCP (2bytes)------->|<-Application-><--CRC--> * <31 30> <29> <28 -16> |<15 -14><13 - 8><7 - 0> |<---Payload---><2 bytes> * <--R--> |< Type >| * */ uint8_t *phBuildHdllCmd(phHDLLCmd_t *hdllCmd) { uint8_t type = 0; uint8_t *hdll_frame = NULL; uint16_t hdll_frame_size = 0; uint16_t hdll_crc = 0x0; uint16_t hdll_header = 0x0; NXPLOG_FWDNLD_D("phBuildHdllCmd:\n"); if (NULL == hdllCmd) { return NULL; } // header len =2 bytes + hdll_payload_len + crc =2 bytes hdll_frame_size = HDLL_HEADER_LEN + HCP_MSG_HEADER_LEN + hdllCmd->payload_len + HDLL_CRC_LEN; hdll_frame = (uint8_t *)malloc(sizeof(uint8_t) * hdll_frame_size); if (NULL == hdll_frame) { return hdll_frame; } // build hdll frame hdll_header |= hdllCmd->payload_len + HCP_MSG_HEADER_LEN; hdll_header &= HDLL_PKT_LEN_BITMASK; hdll_header = hdllCmd->chunk_size ? (HDLL_PKT_CHUNK_BITMASK | hdll_header) : hdll_header; // hdll_header uint16 to uint8 hdll_frame[HDLL_CHUNK_OFFSET] = (hdll_header >> 8); hdll_frame[HDLL_LEN_OFFSET] = (hdll_header & 0xFF); type = HCP_TYPE_COMMAND; type <<= HCP_GROUP_LEN; hdll_frame[HDLL_TYPE_OFFSET] = type | hdllCmd->group; hdll_frame[HDLL_OPERATION_OFFSET] = hdllCmd->operation; if (hdllCmd->payload_len > 0 && hdllCmd->payload != NULL) { // copy hdll payload into hdll frame memcpy(&hdll_frame[HDLL_PAYLOAD_OFFSET], hdllCmd->payload, hdllCmd->payload_len); } hdll_crc = phHal_Host_CalcCrc16(hdll_frame, hdll_frame_size - 2); hdll_frame[hdll_frame_size - 2] = (hdll_crc >> 8); hdll_frame[hdll_frame_size - 1] = (hdll_crc & 0xFF); hdllCmd->frame_size = hdll_frame_size; return hdll_frame; } /******************************************************************************* ** ** Function : sendEdlResetCmd ** ** Description : This function frames the EdlResetCmd and sends to the HeliosX chip ** ** Parameters : None ** ** Returns : FW_DNLD_FAILURE - If any failure occurs while framing or sending the command or while receiving the response FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t sendEdlResetCmd() { uint8_t rsp_buf[HDLL_READ_BUFF_SIZE] = {0}; uint8_t *hdll_frame = NULL; phFWD_Status_t ret = FW_DNLD_FAILURE; uint16_t rsp_buf_len = 0x0; phHDLLCmd_t *hdllCmd = NULL; phHDLLCmdRsp_t *hdllCmdRsp = NULL; hdllCmd = (phHDLLCmd_t *)malloc(sizeof(phHDLLCmd_t)); if (NULL == hdllCmd) { goto exit; } hdllCmd->group = HCP_OPERATION_GROUP_GENERIC; hdllCmd->operation = GENERIC_GROUP_OP_CODE_RESET; hdllCmd->chunk_size = 0; hdllCmd->frame_size = 0; hdllCmd->payload = NULL; hdllCmd->payload_len = 0; hdll_frame = phBuildHdllCmd(hdllCmd); if (NULL == hdll_frame) { goto exit; } NXPLOG_FWDNLD_D("Sending operation: OP_GENERIC_RESET\n"); ret = phGenericSendAndRecv(hdll_frame, hdllCmd->frame_size, rsp_buf, &rsp_buf_len); if (ret == FW_DNLD_FAILURE) { // treat is as success as generic reset will have response only if there // is an error. ret = FW_DNLD_SUCCESS; } if (rsp_buf_len > 0) { hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { ret = FW_DNLD_FAILURE; goto exit; } hdllCmdRsp->group = HCP_OPERATION_GROUP_GENERIC; hdllCmdRsp->operation = GENERIC_GROUP_OP_CODE_RESET; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); } exit: if (hdll_frame != NULL) { free(hdll_frame); } if (NULL != hdllCmd) { free(hdllCmd); } if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : phGetEdlReadyNtf ** ** Description : This function frames the GetEdlReadyNtf command and sends to the HeliosX chip ** ** Parameters : None ** ** Returns : FW_DNLD_FAILURE - If any failure occurs while framing or sending the command or while receiving the response FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t phGetEdlReadyNtf() { uint8_t rsp_buf[HDLL_READ_BUFF_SIZE] = {0}; phFWD_Status_t ret = FW_DNLD_FAILURE; uint16_t rsp_buf_len = 0x0; phHDLLCmdRsp_t *hdllCmdRsp = NULL; NXPLOG_FWDNLD_D("Wait for EDL_READY notification\n"); ret = phHdll_GetApdu((uint8_t *)&rsp_buf[0], HDLL_READ_BUFF_SIZE, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving GET_EDL_READY cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_PROTOCOL; hdllCmdRsp->operation = PROTOCOL_GROUP_OP_CODE_EDL; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = READY; hdllCmdRsp->type = HCP_TYPE_NOTIFICATION; ret = process_hdll_response(hdllCmdRsp); if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : phGenericGetInfo ** ** Description : This function frames the GenericGetInfo command and sends to the HeliosX chip ** ** Parameters : None ** ** Returns : FW_DNLD_FAILURE - If any failure occurs while framing or sending the command or while receiving the response FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t phGenericGetInfo() { uint8_t rsp_buf[HDLL_READ_BUFF_SIZE] = {0}; uint8_t *hdll_frame = NULL; phFWD_Status_t ret = FW_DNLD_FAILURE; uint16_t rsp_buf_len = 0x0; phHDLLCmd_t *hdllCmd = NULL; phHDLLCmdRsp_t *hdllCmdRsp = NULL; hdllCmd = (phHDLLCmd_t *)malloc(sizeof(phHDLLCmd_t)); if (NULL == hdllCmd) { ret = FW_DNLD_FAILURE; goto exit; } hdllCmd->group = HCP_OPERATION_GROUP_GENERIC; hdllCmd->operation = GENERIC_GROUP_OP_CODE_GETINFO; hdllCmd->chunk_size = 0; hdllCmd->frame_size = 0; hdllCmd->payload = NULL; hdllCmd->payload_len = 0; hdll_frame = phBuildHdllCmd(hdllCmd); if (NULL == hdll_frame) { goto exit; } NXPLOG_FWDNLD_D("Sending operation: OP_GENERIC_GET_INFO\n"); ret = phGenericSendAndRecv(hdll_frame, hdllCmd->frame_size, rsp_buf, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in sending/receiving hdll cmd/response\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { ret = FW_DNLD_FAILURE; goto exit; } hdllCmdRsp->group = HCP_OPERATION_GROUP_GENERIC; hdllCmdRsp->operation = GENERIC_GROUP_OP_CODE_GETINFO; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = GENERIC_SUCCESS; hdllCmdRsp->type = HCP_TYPE_RESPONSE; ret = process_hdll_response(hdllCmdRsp); exit: if (NULL != hdll_frame) { free(hdll_frame); } if (NULL != hdllCmd) { free(hdllCmd); } if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : phHdll_GetHdllReadyNtf ** ** Description : This function frames the GetHdllReadyNtf command and sends to the HeliosX chip ** ** Parameters : None ** ** Returns : FW_DNLD_FAILURE - If any failure occurs while framing or sending the command or while receiving the response FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t phHdll_GetHdllReadyNtf() { uint8_t rsp_buf[HDLL_READ_BUFF_SIZE] = {0}; phFWD_Status_t ret = FW_DNLD_FAILURE; uint16_t rsp_buf_len = 0x0; phHDLLCmdRsp_t *hdllCmdRsp = NULL; NXPLOG_FWDNLD_D("Wait for HDL_READY notification\n"); ret = phHdll_GetApdu((uint8_t *)&rsp_buf[0], HDLL_READ_BUFF_SIZE, &rsp_buf_len); if (!rsp_buf_len || ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_D("Error in reading GET_HDL_READY notification\n"); return ret; } hdllCmdRsp = (phHDLLCmdRsp_t *)malloc(sizeof(phHDLLCmdRsp_t)); if (NULL == hdllCmdRsp) { return ret; } hdllCmdRsp->group = HCP_OPERATION_GROUP_PROTOCOL; hdllCmdRsp->operation = PROTOCOL_GROUP_OP_CODE_HDLL; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = READY; hdllCmdRsp->type = HCP_TYPE_NOTIFICATION; ret = process_hdll_response(hdllCmdRsp); if (FW_DNLD_SUCCESS != ret) { // check whether we received EDL ready notification or not // if yes, perform FW download directly. hdllCmdRsp->group = HCP_OPERATION_GROUP_PROTOCOL; hdllCmdRsp->operation = PROTOCOL_GROUP_OP_CODE_EDL; hdllCmdRsp->rsp_buf = rsp_buf; hdllCmdRsp->rsp_buf_len = rsp_buf_len; hdllCmdRsp->status = READY; hdllCmdRsp->type = HCP_TYPE_NOTIFICATION; ret = process_hdll_response(hdllCmdRsp); if (FW_DNLD_SUCCESS == ret) { bSkipEdlCheck = true; } } if (NULL != hdllCmdRsp) { free(hdllCmdRsp); } return ret; } /******************************************************************************* ** ** Function : phEdl_send_and_recv ** ** Description : This function sends and receives the EDL group commands and responses based on the given operation code. ** ** Parameters : hdll_data - HDLL command buffer hdll_data_len - HDLL command buffer len group - HCP group code operation - operation code. ** ** Returns : FW_DNLD_FAILURE - If any failure occurs while framing or sending the command or while receiving the response FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t phEdl_send_and_recv(uint8_t *hdll_data, uint32_t hdll_data_len, uint8_t group, uint8_t operation) { phFWD_Status_t ret = FW_DNLD_FAILURE; uint8_t rsp_buff[HDLL_READ_BUFF_SIZE] = {0}; if (group != HCP_OPERATION_GROUP_EDL) { NXPLOG_FWDNLD_D("Error! HCP operation group is not EDL\n"); return ret; } switch (operation) { case EDL_DOWNLOAD_CERTIFICATE: { ret = sendEdlDownloadCertificateCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_DOWNLOAD_FLASH_WRITE_FIRST: { ret = sendEdlFlashWriteFirstCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_DOWNLOAD_FLASH_WRITE: { ret = sendEdlFlashWriteCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_DOWNLOAD_FLASH_WRITE_LAST: { ret = sendEdlFlashWriteLastCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_LIFECYCLE_CERTIFICATE: { ret = sendEdlLifecycleCertificateCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_LIFECYCLE_WRITE_FIRST: { ret = sendEdlLifecycleWriteFirstCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_LIFECYCLE_WRITE_LAST: { ret = sendEdlLifecycleWriteLastCmd(hdll_data, hdll_data_len, rsp_buff); } break; case EDL_PATCH_FLASH_WRITE: { ret = sendEdlPatchFlashWriteCmd(hdll_data, hdll_data_len, rsp_buff); } break; default: break; } return ret; } /******************************************************************************* ** ** Function : phLoadFwBinary ** ** Description : This function reads the MW FW binary file and writes to HeliosX chip. ** ** Parameters : pfwImageCtx -> pointer to fw image context ** ** Returns : FW_DNLD_FAILURE - on failure FW_DNLD_SUCCESS - On success ** ** *******************************************************************************/ phFWD_Status_t phLoadFwBinary(phUwbFWImageContext_t *pfwImageCtx) { uint32_t next_frame_first_byte_index = 0; uint8_t current_op_group; uint8_t current_op; uint32_t frame_payload_length = 0; uint32_t frame_length = 0; phFWD_Status_t status = FW_DNLD_FAILURE; uint8_t current_frame[MAX_FRAME_LEN] = {0}; if (NULL == pfwImageCtx->fwImage) { return status; } NXPLOG_FWDNLD_D("phLoadFwBinary\n"); while (1) { // compute next frame payload length // TODO: warning this is not HDLL fragmentation compatible (valid header can // have chunk flag (biy 10 (13)) set) Assuming header length is 2 bytes frame_payload_length = (pfwImageCtx->fwImage[next_frame_first_byte_index] << 8) + (pfwImageCtx->fwImage[next_frame_first_byte_index + 1]); // if max_payload_length is not None and (frame_payload_length >= // max_payload_length): raise Exception('Invalid SFWU content (not an HDLL // header).') // copy the header, the payload and the footer (crc) from the file bytes // into a byte array frame_length = frame_payload_length + HDLL_HEADER_LEN + HDLL_FOOTER_LEN; if (frame_length > MAX_FRAME_LEN) { NXPLOG_FWDNLD_E("%s: Error while performing FW download frame_length > " "MAX_FRAME_LEN\n", __func__); status = FW_DNLD_FAILURE; break; } memcpy(current_frame, &pfwImageCtx->fwImage[next_frame_first_byte_index], frame_length); current_op_group = current_frame[2]; current_op = current_frame[3]; status = phEdl_send_and_recv(current_frame, frame_length, current_op_group, current_op); if (status != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s: Error while performing FW download\n", __func__); break; } // update byte index next_frame_first_byte_index = next_frame_first_byte_index + frame_length; // check end of file if (next_frame_first_byte_index >= pfwImageCtx->fwImgSize) { break; } } // clean-up if (pfwImageCtx->fwImage != NULL) { if (pfwImageCtx->fw_dnld_config == BIN_FILE_BASED_FW_DOWNLOAD) { free(pfwImageCtx->fwImage); } else if (pfwImageCtx->fw_dnld_config == SO_FILE_BASED_FW_DOWNLOAD) { if (pfwImageCtx->gFwLib != NULL) { dlclose(pfwImageCtx->gFwLib); pfwImageCtx->gFwLib = NULL; } } pfwImageCtx->fwImage = NULL; } return status; } /****************************************************************************** * Function phHandle_hdll_read_timeout_cb * * Description Timer call back function * * Returns None * ******************************************************************************/ static void phHandle_hdll_read_timeout_cb(uint32_t timerId, void *pContext) { UNUSED(timerId); UNUSED(pContext); NXPLOG_FWDNLD_E("ERROR: phHandle_hdll_read_timeout_cb - HDLL read timeout\n"); ioctl((intptr_t)tPalConfig.pDevHandle, SRXXX_SET_PWR, ABORT_READ_PENDING); isHdllReadTmeoutExpired = true; } /******************************************************************************/ /* GLOBAL FUNCTIONS */ /******************************************************************************/ /******************************************************************************* ** ** Function : phHdll_GetApdu ** ** Description : This function reads the HDLL command's response from HeliosX chip over SPI. ** ** Parameters : pApdu - HDLL response buffer sz - Max buffer size to be read rsp_buf_len - HDLL response buffer length ** ** Returns : phFWD_Status_t : 0 - success 1 - failure ** ** *******************************************************************************/ phFWD_Status_t phHdll_GetApdu(uint8_t *pApdu, uint16_t sz, uint16_t *rsp_buf_len) { // NXPLOG_FWDNLD_D("phHdll_GetApdu Enter\n"); int ret_len = 0; int status = 0; if (sz == 0 || sz > PHHDLL_MAX_LEN_PAYLOAD_MISO) { NXPLOG_FWDNLD_E("ERROR: phHdll_GetApdu data len is 0 or greater than max " "palyload length supported\n"); return FW_DNLD_FAILURE; } /* Start timer */ status = phOsalUwb_Timer_Start(timeoutTimerId, HDLL_READ_OP_TIMEOUT, &phHandle_hdll_read_timeout_cb, NULL); if (UWBSTATUS_SUCCESS != status) { NXPLOG_FWDNLD_E("%s: Response timer not started!!!", __func__); return FW_DNLD_FAILURE; } ret_len = read((intptr_t)tPalConfig.pDevHandle, (void *)pApdu, (sz)); if (true == isHdllReadTmeoutExpired) { isHdllReadTmeoutExpired = false; return FW_DNLD_FAILURE; } else { /* Stop Timer */ status = phOsalUwb_Timer_Stop(timeoutTimerId); if (UWBSTATUS_SUCCESS != status) { NXPLOG_FWDNLD_E("%s: Response timer stop ERROR!!!", __func__); return FW_DNLD_FAILURE; } } if (ret_len <= 0) { NXPLOG_FWDNLD_E("ERROR: Get APDU %u bytes failed!\n", sz); return FW_DNLD_FAILURE; } *rsp_buf_len = ret_len; if (is_fw_download_log_enabled == 0x01) { phNxpUciHal_print_packet(NXP_TML_FW_DNLD_RSP_UWBS_2_AP, pApdu, ret_len); } return FW_DNLD_SUCCESS; } /******************************************************************************* ** ** Function : phHdll_PutApdu ** ** Description : This function sends the HDLL command to HeliosX chip over SPI ** ** Parameters : pApdu - HDLL command to be sent sz - HDLL command length ** ** Returns : phFWD_Status_t : 0 - success 1 - failure ** ** *******************************************************************************/ phFWD_Status_t phHdll_PutApdu(uint8_t *pApdu, uint16_t sz) { int ret; int numWrote = 0; if (is_fw_download_log_enabled == 0x01) { phNxpUciHal_print_packet(NXP_TML_FW_DNLD_CMD_AP_2_UWBS, pApdu, sz); } ret = write((intptr_t)tPalConfig.pDevHandle, pApdu, sz); if (ret > 0) { numWrote += ret; } else if (ret == 0) { NXPLOG_FWDNLD_E("_spi_write() EOF"); return FW_DNLD_FAILURE; } else { NXPLOG_FWDNLD_E("_spi_write() errno : %x", ret); return FW_DNLD_FAILURE; } return FW_DNLD_SUCCESS; } /******************************************************************************* * Function hdll_fw_download * * Description This function is called by jni when wired mode is * performed.First SRXXX driver will give the access * permission whether wired mode is allowed or not * arg (0): * Returns FW_DNLD_SUCCESS - on success FW_DNLD_FAILURE - on failure FW_DNLD_FILE_NOT_FOUND - if the FW binary is not found or unable to open * ******************************************************************************/ int hdll_fw_download() { phFWD_Status_t ret = FW_DNLD_FAILURE; unsigned long num = 0; NXPLOG_FWDNLD_D("hdll_fw_download enter.....\n"); isHdllReadTmeoutExpired = false; bSkipEdlCheck = false; if (NxpConfig_GetNum(NAME_UWB_FW_DOWNLOAD_LOG, &num, sizeof(num))) { is_fw_download_log_enabled = (uint8_t)num; ALOGD("NAME_UWB_FW_DOWNLOAD_LOG: 0x%02x\n", is_fw_download_log_enabled); } else { ALOGD("NAME_UWB_FW_DOWNLOAD_LOG: failed 0x%02x\n", is_fw_download_log_enabled); } ioctl((intptr_t)tPalConfig.pDevHandle, SRXXX_SET_FWD, PWR_ENABLE); ret = phHdll_GetHdllReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s:%d error in getting the hdll ready notification...\n", __func__,__LINE__); return ret; } /* Get the Device information */ ret = phGenericGetInfo(); if (ret == FW_DNLD_FILE_NOT_FOUND) { goto exit; } if (ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_E("%s: error in getting the getInfo notification...\n", __func__); return ret; } if (!bSkipEdlCheck) { if (ret == FW_DNLD_NOT_REQUIRED) { goto exit; } ret = phGetEdlReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s: error in getting the EDL ready notification...\n", __func__); return ret; } } if(fwImageCtx.fwRecovery) { /* perform FW recovery */ ret = phNxpUciHal_fw_recovery(&fwImageCtx); if (ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_E("%s: error downloading recovery FW...\n", __func__); return ret; } // TODO: Remove this after recovrry FW tested added to avoid endless loop of fw download. fwImageCtx.fwRecovery = false; } /* */ ret = phLoadFwBinary(&fwImageCtx); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s: error in phLoadFwBinary...\n", __func__); return ret; } exit: // do chip reset phTmlUwb_Chip_Reset(); ret = phHdll_GetHdllReadyNtf(); ioctl((intptr_t)tPalConfig.pDevHandle, SRXXX_SET_FWD, PWR_DISABLE); NXPLOG_FWDNLD_D("hdll_fw_download completed.....\n"); return ret; } /******************************************************************************* * Function phNxpUciHal_fw_recovery * * Description This function is use to download recovery FW * Returns FW_DNLD_SUCCESS - on success FW_DNLD_FAILURE - on failure FW_DNLD_FILE_NOT_FOUND - if the FW binary is not found or unable to open * ******************************************************************************/ static phFWD_Status_t phNxpUciHal_fw_recovery(phUwbFWImageContext_t *pfwImageCtx) { phFWD_Status_t ret = FW_DNLD_FAILURE; NXPLOG_FWDNLD_D("phNxpUciHal_fw_recovery enter.....\n"); ret = phLoadFwBinary(pfwImageCtx); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s: error in phLoadFwBinary...\n", __func__); return ret; } // do chip reset phTmlUwb_Chip_Reset(); ret = phHdll_GetHdllReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s:%d error in getting the hdll ready notification...\n", __func__,__LINE__); return ret; } /* Get the Device information */ ret = phGenericGetInfo(); if (ret == FW_DNLD_FAILURE || ret == FW_DNLD_FILE_NOT_FOUND) { NXPLOG_FWDNLD_E("%s:%d error in getting the getInfo notification...\n", __func__,__LINE__); return ret; } if (!bSkipEdlCheck) { if (ret == FW_DNLD_NOT_REQUIRED) { return ret; } ret = phGetEdlReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s:%d error in getting the EDL ready notification...\n", __func__,__LINE__); return ret; } } return ret; } /******************************************************************************* * Function phNxpUciHal_fw_lcrotation * * Description This function is use to download recovery FW * Returns FW_DNLD_SUCCESS - on success FW_DNLD_FAILURE - on failure FW_DNLD_FILE_NOT_FOUND - if the FW binary is not found or unable to open * ******************************************************************************/ phFWD_Status_t phNxpUciHal_fw_lcrotation() { phFWD_Status_t ret = FW_DNLD_FAILURE; glcRotation = true; NXPLOG_FWDNLD_D("phNxpUciHal_fw_lcrotation enter.....\n"); ioctl((intptr_t)tPalConfig.pDevHandle, SRXXX_SET_FWD, PWR_ENABLE); ret = phHdll_GetHdllReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s:%d error in getting the hdll ready notification...\n", __func__,__LINE__); return ret; } /* Get the Device information */ ret = phGenericGetInfo(); if (ret == FW_DNLD_FILE_NOT_FOUND) { goto exit; } if (ret == FW_DNLD_FAILURE) { NXPLOG_FWDNLD_E("%s:%d error in getting the getInfo notification...\n", __func__,__LINE__); return ret; } if (!bSkipEdlCheck) { ret = phGetEdlReadyNtf(); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s:%d error in getting the EDL ready notification...\n", __func__,__LINE__); return ret; } } ret = phLoadFwBinary(&fwImageCtx); if (ret != FW_DNLD_SUCCESS) { NXPLOG_FWDNLD_E("%s: error in phLoadFwBinary...\n", __func__); glcRotation = false; return ret; } glcRotation = false; exit: // do chip reset phTmlUwb_Chip_Reset(); ret = phHdll_GetHdllReadyNtf(); ioctl((intptr_t)tPalConfig.pDevHandle, SRXXX_SET_FWD, PWR_DISABLE); NXPLOG_FWDNLD_D("hdll_fw_download completed.....\n"); return ret; } /******************************************************************************* * Function setDeviceHandle * * Description This function sets the SPI device handle that needs to be used in this file for SPI communication * Parameters pDevHandle - SPI device handle * Returns None * ******************************************************************************/ void setDeviceHandle(void *pDevHandle) { NXPLOG_FWDNLD_D("Set the device handle!\n"); if (pDevHandle == NULL) { NXPLOG_FWDNLD_E("device handle is NULL!\n"); } else { tPalConfig.pDevHandle = (void *)((intptr_t)pDevHandle); } }