blob: 45145ca6629769c70612e7b8e466ec4834ad64d3 [file] [log] [blame]
/*
* 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 <sys/ioctl.h>
#include <dlfcn.h>
#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> |<status><Payload><2 bytes>
* <--R--><Chunk><length> |< Type ><Group><Operation>|<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--> <Chunk> <length> |< Type ><Group><Operation>|
*
*/
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);
}
}