Snap for 10447354 from e0d57d01366dbc0a7188ad3b9ec80fb1ce19815d to mainline-cellbroadcast-release

Change-Id: I7c99a82d24f1243b2a4282e007daa657f6b2f9ef
diff --git a/aidl/hal_st21nfc.cc b/aidl/hal_st21nfc.cc
index 755ece1..d3903c7 100644
--- a/aidl/hal_st21nfc.cc
+++ b/aidl/hal_st21nfc.cc
@@ -345,6 +345,7 @@
 }
 
 int StNfc_hal_close(int nfc_mode_value) {
+  void* stdll = nullptr;
   STLOG_HAL_D("HAL st21nfc: %s nfc_mode = %d", __func__, nfc_mode_value);
 
   /* check if HAL is closed */
@@ -371,8 +372,11 @@
   std::string valueStr =
       android::base::GetProperty("persist.vendor.nfc.streset", "");
   if (valueStr.length() > 0) {
-    valueStr = VENDOR_LIB_PATH + valueStr + VENDOR_LIB_EXT;
-    void* stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    if (!stdll) {
+      valueStr = VENDOR_LIB_PATH + valueStr + VENDOR_LIB_EXT;
+      stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    }
     if (stdll) {
       STLOG_HAL_D("STReset Cold reset");
       STEseReset fn = (STEseReset)dlsym(stdll, "cold_reset");
@@ -524,10 +528,10 @@
 
 void StNfc_hal_setLogging(bool enable) {
   dbg_logging = enable;
-  if (dbg_logging) {
+  if (dbg_logging && hal_conf_trace_level < STNFC_TRACE_LEVEL_VERBOSE) {
     hal_trace_level = STNFC_TRACE_LEVEL_VERBOSE;
   } else {
-    hal_trace_level = STNFC_TRACE_LEVEL_ERROR;
+    hal_trace_level = hal_conf_trace_level;
   }
 }
 
diff --git a/aidl/main.cpp b/aidl/main.cpp
index e596386..a9d7275 100644
--- a/aidl/main.cpp
+++ b/aidl/main.cpp
@@ -30,13 +30,17 @@
 typedef int (*STEseReset)(void);
 
 int main() {
+  void* stdll = nullptr;
   LOG(INFO) << "NFC AIDL HAL Service is starting up";
 
   std::string valueStr =
       android::base::GetProperty("persist.vendor.nfc.streset", "");
   if (valueStr.length() > 0) {
-    valueStr = VENDOR_LIB_PATH + valueStr + VENDOR_LIB_EXT;
-    void* stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    if (!stdll) {
+      valueStr = VENDOR_LIB_PATH + valueStr + VENDOR_LIB_EXT;
+      stdll = dlopen(valueStr.c_str(), RTLD_NOW);
+    }
     if (stdll) {
       LOG(INFO) << "ST NFC HAL STReset starting.";
       STEseReset fn = (STEseReset)dlsym(stdll, "boot_reset");
diff --git a/st21nfc/adaptation/android_logmsg.cpp b/st21nfc/adaptation/android_logmsg.cpp
index 341309a..72e5b6a 100644
--- a/st21nfc/adaptation/android_logmsg.cpp
+++ b/st21nfc/adaptation/android_logmsg.cpp
@@ -22,6 +22,7 @@
 
 void DispHal(const char* title, const void* data, size_t length);
 unsigned char hal_trace_level = STNFC_TRACE_LEVEL_DEBUG;
+unsigned char hal_conf_trace_level = STNFC_TRACE_LEVEL_DEBUG;
 uint16_t hal_log_cnt = 0;
 pthread_mutex_t halLogMutex;
 
@@ -49,8 +50,10 @@
   int ret;
 
   num = 1;
-  if (GetNumValue(NAME_STNFC_HAL_LOGLEVEL, &num, sizeof(num)))
-    hal_trace_level = (unsigned char)num;
+  if (GetNumValue(NAME_STNFC_HAL_LOGLEVEL, &num, sizeof(num))) {
+    hal_conf_trace_level = (unsigned char)num;
+    hal_trace_level = hal_conf_trace_level;
+  }
 
   STLOG_HAL_D("%s: HAL log level=%u, hal_log_cnt (before reset): #%04X",
               __func__, hal_trace_level, hal_log_cnt);
@@ -123,13 +126,15 @@
           STLOG_HAL_D("%s\n", line);
         }
       }
-      line[k] = 0;
+      if (k < 100) {
+        line[k] = 0;
+      }
     }
-    sprintf(&line[k * 3], "%02x ", d[i]);
+    snprintf(&line[k * 3], sizeof(line) - (k * 3), "%02x ", d[i]);
   }
 
   if (privacy) {
-    sprintf(&line[k * 3], "(hidden)");
+    snprintf(&line[k * 3], sizeof(line) - (k * 3), "(hidden)");
   }
 
   if (first_line == true) {
diff --git a/st21nfc/adaptation/i2clayer.cc b/st21nfc/adaptation/i2clayer.cc
index 4cad4db..4cbff2e 100644
--- a/st21nfc/adaptation/i2clayer.cc
+++ b/st21nfc/adaptation/i2clayer.cc
@@ -113,7 +113,12 @@
     int poll_status = poll(event_table, eventNum, -1);
 
     if (-1 == poll_status) {
-      STLOG_HAL_E("error in poll call\n");
+      poll_status = errno;
+      STLOG_HAL_E("error in poll call : %d - %s\n", poll_status,
+                  strerror(poll_status));
+      if ((poll_status == EINTR) || (poll_status == EAGAIN)) continue;
+
+      // other errors, we stop.
       break;
     }
 
@@ -235,6 +240,9 @@
     }
   } while (!closeThread);
 
+  // Stop here if we got a serious error above.
+  assert(closeThread);
+
   close(fidI2c);
   close(cmdPipe[0]);
   close(cmdPipe[1]);
diff --git a/st21nfc/hal/hal_fd.cc b/st21nfc/hal/hal_fd.cc
index 2e8fab0..810aca3 100644
--- a/st21nfc/hal/hal_fd.cc
+++ b/st21nfc/hal/hal_fd.cc
@@ -55,6 +55,51 @@
 
 static const uint8_t ApduExitLoadMode[] = {0x2F, 0x04, 0x06, 0x80, 0xA0,
                                            0x00, 0x00, 0x01, 0x01};
+
+// APDUs for ST54L
+const int UK_NB = 2;
+const int UK_SIZE = 12;
+static uint8_t UserKeys[UK_NB][UK_SIZE] = {
+    {0x00, 0x00, 0xFD, 0x0F, 0x87, 0x7D, 0x31, 0xE3, 0xCF, 0x0C, 0xD3,
+     0x68},  // Test
+    {0x00, 0x00, 0xFD, 0x00, 0x87, 0x7D, 0x31, 0xE3, 0xCF, 0x0C, 0xD3,
+     0x68}};  // Production
+
+static uint8_t ApduPutKeyUser1[UK_NB][50] = {
+    {0x2F, 0x04, 0x2F, 0x84, 0x11, 0x00, 0x00, 0x2A, 0x01, 0xB3,
+     0x56, 0x01,  // Test
+     0x00, 0x00, 0xFD, 0x20, 0x20, 0xEC, 0x7D, 0x47, 0xAE, 0xF3,
+     0x23, 0x2E, 0x00, 0x00, 0x34, 0x78, 0x82, 0xEC, 0x6b, 0xA5,
+     0x83, 0xAF, 0x68, 0xC7, 0x1F, 0x9F, 0xB0, 0xD7, 0x9D, 0x33,
+     0xB0, 0xDA, 0xC6, 0x2C, 0xAB, 0x8A, 0x10, 0xEA},
+    {0x2F, 0x04, 0x2F, 0x84, 0x11, 0x00, 0x00, 0x2A, 0x01, 0xB3,
+     0x56, 0x01,  // Production
+     0x00, 0x00, 0xFD, 0x20, 0x20, 0xEC, 0x7D, 0x47, 0xAE, 0xF3,
+     0x23, 0x2E, 0x00, 0x00, 0xE1, 0xA2, 0x78, 0xA9, 0x71, 0x14,
+     0x46, 0x6D, 0x73, 0x86, 0x4C, 0x3B, 0x0F, 0x51, 0x71, 0x8E,
+     0xE4, 0x1D, 0x54, 0x02, 0x3A, 0xE3, 0x18, 0x55}};
+
+static uint8_t ApduEraseUpgradeStart[] = {
+    0x2F, 0x04, 0x12, 0x84, 0x35, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0xB2, 0x51, 0x42, 0xB0, 0x27, 0x92, 0xAA, 0xAB};
+
+static uint8_t ApduEraseNfcArea[] = {0x2F, 0x04, 0x17, 0x84, 0x36, 0x00, 0x00,
+                                     0x12, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00,
+                                     0x00, 0x04, 0x5E, 0x00, 0x4D, 0x83, 0xE1,
+                                     0x59, 0x62, 0xDC, 0x14, 0x64};
+
+static uint8_t ApduEraseUpgradeStop[] = {0x2F, 0x04, 0x0F, 0x80, 0x33, 0x00,
+                                         0x00, 0x0A, 0x00, 0x02, 0x97, 0x22,
+                                         0xC2, 0x5A, 0x2D, 0xA4, 0x09, 0x1A};
+
+static uint8_t ApduSetVariousConfig[] = {
+    0x2F, 0x04, 0x11, 0x84, 0x74, 0x00, 0x00, 0x0C, 0x06, 0x02,
+    0x80, 0x80, 0xD4, 0x29, 0xEC, 0x9A, 0xFB, 0xC8, 0x4B, 0x2A};
+
+static uint8_t ApduSwitchToUser[] = {0x2F, 0x04, 0x0F, 0x84, 0xA0, 0x00,
+                                     0x00, 0x0A, 0x20, 0x01, 0xFC, 0x63,
+                                     0x2A, 0xE1, 0xFD, 0xAA, 0xD1, 0x9B};
+
 static const uint8_t nciHeaderPropSetUwbConfig[9] = {
     0x2F, 0x02, 0x00, 0x04, 0x00, 0x16, 0x01, 0x00, 0x00};
 static const uint8_t nciGetPropConfig[8] = {0x2F, 0x02, 0x05, 0x03,
@@ -64,12 +109,44 @@
 static uint8_t nciPropSetUwbConfig[128];
 static uint8_t nciPropSetConfig_CustomField[64];
 hal_fd_state_e mHalFDState = HAL_FD_STATE_AUTHENTICATE;
+hal_fd_st54l_state_e mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER;
 void SendExitLoadMode(HALHANDLE mmHalHandle);
+void SendSwitchToUserMode(HALHANDLE mmHalHandle);
 extern void hal_wrapper_update_complete();
 
 typedef size_t (*STLoadUwbParams)(void *out_buff,
                                   size_t buf_size);
 
+/***********************************************************************
+ * Determine UserKey
+ *
+ * @return mode: -1 : not supported
+ *                0 : Test sample
+ *                1 : Product sample
+ ***********************************************************************/
+static int GetProdType(uint8_t* UserKey) {
+  int i, j;
+  int status;
+
+  for (i = 0; i < UK_NB; i++) {
+    status = 1;
+    for (j = 0; j < UK_SIZE; j++) {
+      if (UserKey[j] != UserKeys[i][j]) {
+        STLOG_HAL_D(
+            "   No match between UserKey[%d]=0x%02X and \
+                UserKeys[%d][%d]=0x%02X",
+            j, UserKey[j], i, j, UserKeys[i][j]);
+        status = 0;
+        break;
+      }
+    }
+    if (1 == status) {
+      return i;
+    }
+  }
+  return (-1);
+}
+
 /**
  * Send a HW reset and decode NCI_CORE_RESET_NTF information
  * @param pHwVersion is used to return HW version, part of NCI_CORE_RESET_NTF
@@ -90,6 +167,7 @@
   char ConfPath[256];
   char fwBinName[256];
   char fwConfName[256];
+  int ret;
 
   STLOG_HAL_D("  %s - enter", __func__);
 
@@ -142,19 +220,56 @@
     STLOG_HAL_D("%s - %s not detected", __func__, fwBinName);
   } else {
     STLOG_HAL_D("%s - %s file detected\n", __func__, fwBinName);
-
     result |= FW_PATCH_AVAILABLE;
-    fread(mBinData, sizeof(uint8_t), 4, mFwFileBin);
-    mFWInfo->patchVersion =
+
+    ret = fread(mBinData, sizeof(uint8_t), 4, mFwFileBin);
+    if (ret != 4) {
+      STLOG_HAL_E("%s did not read 4 bytes \n", __func__);
+    }
+    mFWInfo->fileFwVersion =
         mBinData[0] << 24 | mBinData[1] << 16 | mBinData[2] << 8 | mBinData[3];
 
-    fread(mApduAuthent, sizeof(uint8_t), 24, mFwFileBin);
-
     fgetpos(mFwFileBin, &mPosInit);
+    ret = fread(mBinData, sizeof(uint8_t), 5, mFwFileBin);
+    if (ret != 5) {
+      STLOG_HAL_E("%s did not read 5 bytes \n", __func__);
+    }
+    fsetpos(mFwFileBin, &mPosInit);  // reset pos in stream
 
-    STLOG_HAL_D(
-        "%s --> st21nfc_fw integrates patch NFC FW version 0x%08X (%s)\n",
-        __func__, mFWInfo->patchVersion, FwType);
+    if (mBinData[4] == 0x35) {
+      mFWInfo->fileHwVersion = HW_ST54L;
+    } else {
+      ret = fread(mApduAuthent, sizeof(uint8_t), 24, mFwFileBin);
+      if (ret != 24) {
+        STLOG_HAL_E("%s Wrong read nb \n", __func__);
+      }
+
+      // We use the last byte of the auth command to discriminate at the moment.
+      // it can be extended in case of conflict later.
+      switch (mApduAuthent[23]) {
+        case 0x43:
+        case 0xC7:
+          mFWInfo->fileHwVersion = HW_NFCD;
+          break;
+
+        case 0xE9:
+          mFWInfo->fileHwVersion = HW_ST54J;
+          break;
+      }
+    }
+
+    if (mFWInfo->fileHwVersion == 0) {
+      STLOG_HAL_E("%s --> %s integrates unknown patch NFC FW -- rejected\n",
+                  __func__, FwPath);
+      fclose(mFwFileBin);
+      mFwFileBin = NULL;
+    } else {
+      fgetpos(mFwFileBin, &mPosInit);
+
+      STLOG_HAL_D("%s --> %s integrates patch NFC FW version 0x%08X (r:%d)\n",
+                  __func__, FwPath, mFWInfo->fileFwVersion,
+                  mFWInfo->fileHwVersion);
+    }
   }
 
   if ((mCustomFileBin = fopen((char *)ConfPath, "r")) == NULL) {
@@ -162,9 +277,9 @@
   } else {
     STLOG_HAL_D("%s - %s file detected\n", __func__, ConfPath);
     fread(mBinData, sizeof(uint8_t), 2, mCustomFileBin);
-    mFWInfo->confVersion = mBinData[0] << 8 | mBinData[1];
+    mFWInfo->fileCustVersion = mBinData[0] << 8 | mBinData[1];
     STLOG_HAL_D("%s --> st21nfc_custom configuration version 0x%04X \n",
-                __func__, mFWInfo->confVersion);
+                __func__, mFWInfo->fileCustVersion);
     result |= FW_CUSTOM_PARAM_AVAILABLE;
   }
 
@@ -215,25 +330,26 @@
     STLOG_HAL_D("-> Router Mode NCI_CORE_RESET_NTF received after HW Reset");
 
     /* retrieve HW Version from NCI_CORE_RESET_NTF */
-    mFWInfo->hwVersion = pdata[8];
-    STLOG_HAL_D("   HwVersion = 0x%02X", mFWInfo->hwVersion);
+    mFWInfo->chipHwVersion = pdata[8];
+    STLOG_HAL_D("   HwVersion = 0x%02X", mFWInfo->chipHwVersion);
 
     /* retrieve FW Version from NCI_CORE_RESET_NTF */
-    mFWInfo->fwVersion =
+    mFWInfo->chipFwVersion =
         (pdata[10] << 24) | (pdata[11] << 16) | (pdata[12] << 8) | pdata[13];
-    STLOG_HAL_D("   FwVersion = 0x%08X", mFWInfo->fwVersion);
+    STLOG_HAL_D("   FwVersion = 0x%08X", mFWInfo->chipFwVersion);
 
     /* retrieve Loader Version from NCI_CORE_RESET_NTF */
-    mFWInfo->loaderVersion = (pdata[14] << 16) | (pdata[15] << 8) | pdata[16];
-    STLOG_HAL_D("   LoaderVersion = 0x%06X", mFWInfo->loaderVersion);
+    mFWInfo->chipLoaderVersion =
+        (pdata[14] << 16) | (pdata[15] << 8) | pdata[16];
+    STLOG_HAL_D("   LoaderVersion = 0x%06X", mFWInfo->chipLoaderVersion);
 
     /* retrieve Customer Version from NCI_CORE_RESET_NTF */
-    mFWInfo->custVersion = (pdata[31] << 8) | pdata[32];
-    STLOG_HAL_D("   CustomerVersion = 0x%04X", mFWInfo->custVersion);
+    mFWInfo->chipCustVersion = (pdata[31] << 8) | pdata[32];
+    STLOG_HAL_D("   CustomerVersion = 0x%04X", mFWInfo->chipCustVersion);
 
     /* retrieve Uwb param Version from NCI_CORE_RESET_NTF */
-    mFWInfo->uwbFwVersion = (pdata[29] << 8) | pdata[30];
-    STLOG_HAL_D("   uwbVersion = 0x%04X", mFWInfo->uwbFwVersion);
+    mFWInfo->chipUwbVersion = (pdata[29] << 8) | pdata[30];
+    STLOG_HAL_D("   uwbVersion = 0x%04X", mFWInfo->chipUwbVersion);
 
     *clf_mode = FT_CLF_MODE_ROUTER;
   } else if ((pdata[2] == 0x39) && (pdata[3] == 0xA1)) {
@@ -241,32 +357,43 @@
 
     /* deduce HW Version from Factory Loader version */
     if (pdata[16] == 0x01) {
-      mFWInfo->hwVersion = 0x05;  // ST54J
+      mFWInfo->chipHwVersion = 0x05;  // ST54J
     } else if (pdata[16] == 0x02) {
-      mFWInfo->hwVersion = 0x04;  // ST21NFCD
+      mFWInfo->chipHwVersion = 0x04;  // ST21NFCD
     } else {
-      mFWInfo->hwVersion = 0x03;  // ST21NFCD
+      mFWInfo->chipHwVersion = 0x03;  // ST21NFCD
     }
-    STLOG_HAL_D("   HwVersion = 0x%02X", mFWInfo->hwVersion);
+    STLOG_HAL_D("   HwVersion = 0x%02X", mFWInfo->chipHwVersion);
 
     /* Identify the Active loader. Normally only one should be detected*/
     if (pdata[11] == 0xA0) {
-      mFWInfo->loaderVersion = (pdata[8] << 16) | (pdata[9] << 8) | pdata[10];
+      mFWInfo->chipLoaderVersion =
+          (pdata[8] << 16) | (pdata[9] << 8) | pdata[10];
       STLOG_HAL_D("         - Most recent loader activated, revision 0x%06X",
-                  mFWInfo->loaderVersion);
+                  mFWInfo->chipLoaderVersion);
     }
     if (pdata[15] == 0xA0) {
-      mFWInfo->loaderVersion = (pdata[12] << 16) | (pdata[13] << 8) | pdata[14];
+      mFWInfo->chipLoaderVersion =
+          (pdata[12] << 16) | (pdata[13] << 8) | pdata[14];
       STLOG_HAL_D("         - Least recent loader activated, revision 0x%06X",
-                  mFWInfo->loaderVersion);
+                  mFWInfo->chipLoaderVersion);
     }
     if (pdata[19] == 0xA0) {
-      mFWInfo->loaderVersion = (pdata[16] << 16) | (pdata[17] << 8) | pdata[18];
+      mFWInfo->chipLoaderVersion =
+          (pdata[16] << 16) | (pdata[17] << 8) | pdata[18];
       STLOG_HAL_D("         - Factory loader activated, revision 0x%06X",
-                  mFWInfo->loaderVersion);
+                  mFWInfo->chipLoaderVersion);
     }
 
     *clf_mode = FT_CLF_MODE_LOADER;
+  } else if ((pdata[2] == 0x41) && (pdata[3] == 0xA2)) {
+    STLOG_HAL_D("-> Loader V3 Mode NCI_CORE_RESET_NTF received after HW Reset");
+    mFWInfo->chipHwVersion = HW_ST54L;
+    STLOG_HAL_D("   HwVersion = 0x%02X", mFWInfo->chipHwVersion);
+    mFWInfo->chipFwVersion = 0;  // make sure FW will be updated.
+    /* retrieve Production type* from NCI_CORE_RESET_NTF */
+    mFWInfo->chipProdType = GetProdType(&pdata[44]);
+    *clf_mode = FT_CLF_MODE_LOADER;
   } else {
     STLOG_HAL_E(
         "%s --> ERROR: wrong NCI_CORE_RESET_NTF received after HW Reset",
@@ -274,17 +401,18 @@
     *clf_mode = FT_CLF_MODE_ERROR;
   }
 
-  // Allow update only for ST54J
-  if (mFWInfo->hwVersion == 0x05) {
-    if ((mFwFileBin != NULL) && (mFWInfo->patchVersion != mFWInfo->fwVersion)) {
+  if ((mFWInfo->chipHwVersion == HW_ST54J) ||
+      (mFWInfo->chipHwVersion == HW_ST54L)) {
+    if ((mFwFileBin != NULL) &&
+        (mFWInfo->fileFwVersion != mFWInfo->chipFwVersion)) {
       STLOG_HAL_D("---> Firmware update needed\n");
       result |= FW_UPDATE_NEEDED;
     } else {
       STLOG_HAL_D("---> No Firmware update needed\n");
     }
 
-    if ((mFWInfo->confVersion != 0) &&
-        (mFWInfo->custVersion != mFWInfo->confVersion)) {
+    if ((mFWInfo->fileCustVersion != 0) &&
+        (mFWInfo->chipCustVersion != mFWInfo->fileCustVersion)) {
       STLOG_HAL_D(
           "%s - Need to apply new st21nfc custom configuration settings\n",
           __func__);
@@ -294,8 +422,8 @@
                   __func__);
     }
   }
-  if ((mFWInfo->uwbVersion != 0) &&
-      (mFWInfo->uwbVersion != mFWInfo->uwbFwVersion)) {
+  if ((mFWInfo->fileUwbVersion != 0) &&
+      (mFWInfo->fileUwbVersion != mFWInfo->chipUwbVersion)) {
     result |= UWB_CONF_UPDATE_NEEDED;
     STLOG_HAL_D("%s - Need to apply new uwb param configuration \n", __func__);
     mUwbConfigNeeded = true;
@@ -401,10 +529,10 @@
       memcpy(nciPropSetUwbConfig, nciHeaderPropSetUwbConfig, 9);
       nciPropSetUwbConfig[2] = lengthOutput + 6;
       nciPropSetUwbConfig[8] = lengthOutput;
-      mFWInfo->uwbVersion =
+      mFWInfo->fileUwbVersion =
           nciPropSetUwbConfig[9] << 8 | nciPropSetUwbConfig[10];
       STLOG_HAL_D("%s --> uwb configuration version 0x%04X \n", __func__,
-                  mFWInfo->uwbVersion);
+                  mFWInfo->fileUwbVersion);
       return true;
     } else {
       STLOG_HAL_D("%s: lengthOutput null", __func__);
@@ -415,11 +543,34 @@
   }
   return false;
 }
+/*******************************************************************************
+**
+** Function         resetHandlerState
+**
+** Description      Reset FW update state.
+**
+** Parameters       void
+**
+**
+*******************************************************************************/
 void resetHandlerState() {
   STLOG_HAL_D("%s", __func__);
   mHalFDState = HAL_FD_STATE_AUTHENTICATE;
+  mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER;
 }
 
+/*******************************************************************************
+**
+** Function         UpdateHandler
+**
+** Description      Handler to update ST54J NFCC FW.
+**
+** Parameters       mHalHandle - HAL handle
+**                  data_len   - Buffer length
+**                  p_data     - Data buffer from NFCC
+**
+**
+*******************************************************************************/
 void UpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t *p_data) {
   HalSendDownstreamStopTimer(mHalHandle);
 
@@ -512,8 +663,9 @@
       STLOG_HAL_D("%s - mHalFDState = HAL_FD_STATE_EXIT_APDU", __func__);
       if ((p_data[data_len - 2] != 0x90) || (p_data[data_len - 1] != 0x00)) {
         STLOG_HAL_D(
-            "%s - Error exiting loader mode, i.e. a problem occured during FW "
-            "update", __func__);
+            "%s - Error exiting loader mode, i.e. a problem occurred"
+            "during FW update",
+            __func__);
       }
 
       I2cResetPulse();
@@ -529,6 +681,176 @@
   }
 }
 
+/*******************************************************************************
+**
+** Function         UpdateHandlerST54L
+**
+** Description      Handler to update ST54L NFCC FW.
+**
+** Parameters       mHalHandle - HAL handle
+**                  data_len   - Buffer length
+**                  p_data     - Data buffer from NFCC
+**
+**
+*******************************************************************************/
+static void UpdateHandlerST54L(HALHANDLE mHalHandle, uint16_t data_len,
+                               uint8_t* p_data) {
+  STLOG_HAL_D("%s : Enter state = %d", __func__, mHalFD54LState);
+
+  switch (mHalFD54LState) {
+    case HAL_FD_ST54L_STATE_PUY_KEYUSER:
+      if (!HalSendDownstreamTimer(
+              mHalHandle, (uint8_t*)ApduPutKeyUser1[mFWInfo->chipProdType],
+              sizeof(ApduPutKeyUser1[mFWInfo->chipProdType]),
+              FW_TIMER_DURATION)) {
+        STLOG_HAL_E("%s - SendDownstream failed", __func__);
+      }
+      mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_UPGRADE_START;
+      break;
+
+    case HAL_FD_ST54L_STATE_ERASE_UPGRADE_START:
+      if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) {
+        if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseUpgradeStart,
+                                    sizeof(ApduEraseUpgradeStart),
+                                    FW_TIMER_DURATION)) {
+          STLOG_HAL_E("%s - SendDownstream failed", __func__);
+        }
+        mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_NFC_AREA;
+      } else {
+        STLOG_HAL_D("%s - FW flash not succeeded", __func__);
+        SendSwitchToUserMode(mHalHandle);
+      }
+      break;
+
+    case HAL_FD_ST54L_STATE_ERASE_NFC_AREA:
+      if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) {
+        if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseNfcArea,
+                                    sizeof(ApduEraseNfcArea),
+                                    FW_TIMER_DURATION)) {
+          STLOG_HAL_E("%s - SendDownstream failed", __func__);
+        }
+        mHalFD54LState = HAL_FD_ST54L_STATE_ERASE_UPGRADE_STOP;
+      } else {
+        STLOG_HAL_D("%s - FW flash not succeeded", __func__);
+        SendSwitchToUserMode(mHalHandle);
+      }
+      break;
+
+    case HAL_FD_ST54L_STATE_ERASE_UPGRADE_STOP:
+      if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) {
+        if (!HalSendDownstreamTimer(mHalHandle, (uint8_t*)ApduEraseUpgradeStop,
+                                    sizeof(ApduEraseUpgradeStop),
+                                    FW_TIMER_DURATION)) {
+          STLOG_HAL_E("%s - SendDownstream failed", __func__);
+        }
+        mHalFD54LState = HAL_FD_ST54L_STATE_SEND_RAW_APDU;
+      } else {
+        STLOG_HAL_D("%s - FW flash not succeeded", __func__);
+        SendSwitchToUserMode(mHalHandle);
+      }
+      break;
+
+    case HAL_FD_ST54L_STATE_SEND_RAW_APDU:
+      STLOG_HAL_D("%s - mHalFDState = HAL_FD_ST54L_STATE_SEND_RAW_APDU",
+                  __func__);
+      if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) {
+        if ((p_data[data_len - 2] == 0x90) && (p_data[data_len - 1] == 0x00)) {
+          mRetry = true;
+
+          fgetpos(mFwFileBin, &mPos);  // save current position in stream
+          if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) &&
+              (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) ==
+               mBinData[2])) {
+            if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3,
+                                        FW_TIMER_DURATION)) {
+              STLOG_HAL_E("%s - SendDownstream failed", __func__);
+            }
+          } else {
+            STLOG_HAL_D("%s - EOF of FW binary", __func__);
+            if (!HalSendDownstreamTimer(
+                    mHalHandle, (uint8_t*)ApduSetVariousConfig,
+                    sizeof(ApduSetVariousConfig), FW_TIMER_DURATION)) {
+              STLOG_HAL_E("%s - SendDownstream failed", __func__);
+            }
+            mHalFD54LState = HAL_FD_ST54L_STATE_SET_CONFIG;
+          }
+        } else if (mRetry == true) {
+          STLOG_HAL_D("%s - Last Tx was NOK. Retry", __func__);
+          mRetry = false;
+          fsetpos(mFwFileBin, &mPos);
+          if ((fread(mBinData, sizeof(uint8_t), 3, mFwFileBin) == 3) &&
+              (fread(mBinData + 3, sizeof(uint8_t), mBinData[2], mFwFileBin) ==
+               mBinData[2])) {
+            if (!HalSendDownstreamTimer(mHalHandle, mBinData, mBinData[2] + 3,
+                                        FW_TIMER_DURATION)) {
+              STLOG_HAL_E("%s - SendDownstream failed", __func__);
+            }
+            fgetpos(mFwFileBin, &mPos);  // save current position in stream
+          } else {
+            STLOG_HAL_D("%s - EOF of FW binary", __func__);
+            if (!HalSendDownstreamTimer(
+                    mHalHandle, (uint8_t*)ApduSetVariousConfig,
+                    sizeof(ApduSetVariousConfig), FW_TIMER_DURATION)) {
+              STLOG_HAL_E("%s - SendDownstream failed", __func__);
+            }
+            mHalFD54LState = HAL_FD_ST54L_STATE_SET_CONFIG;
+          }
+        } else {
+          STLOG_HAL_D("%s - FW flash not succeeded.", __func__);
+          I2cResetPulse();
+          SendSwitchToUserMode(mHalHandle);
+        }
+      }
+      break;
+
+    case HAL_FD_ST54L_STATE_SET_CONFIG:
+
+      if ((p_data[0] == 0x4f) && (p_data[1] == 0x04)) {
+        SendSwitchToUserMode(mHalHandle);
+      }
+      break;
+
+    case HAL_FD_ST54L_STATE_SWITCH_TO_USER:
+      if ((p_data[data_len - 2] != 0x90) || (p_data[data_len - 1] != 0x00)) {
+        STLOG_HAL_D(
+            "%s - Error exiting loader mode, i.e. a problem occurred during FW "
+            "update",
+            __func__);
+      }
+
+      I2cResetPulse();
+      hal_wrapper_set_state(HAL_WRAPPER_STATE_OPEN);
+      mHalFD54LState = HAL_FD_ST54L_STATE_PUY_KEYUSER;
+      break;
+
+    default:
+      STLOG_HAL_D("%s - mHalFD54LState = unknown", __func__);
+      STLOG_HAL_D("%s - FW flash not succeeded", __func__);
+      SendSwitchToUserMode(mHalHandle);
+      break;
+  }
+}
+
+/*******************************************************************************
+**
+** Function         FwUpdateHandler
+**
+** Description      Handler to update NFCC FW.
+**
+** Parameters       mHalHandle - HAL handle
+**                  data_len   - Buffer length
+**                  p_data     - Data buffer from NFCC
+**
+**
+*******************************************************************************/
+void FwUpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t* p_data) {
+  if (mFWInfo->chipHwVersion == HW_ST54L) {
+    UpdateHandlerST54L(mHalHandle, data_len, p_data);
+  } else {
+    UpdateHandler(mHalHandle, data_len, p_data);
+  }
+}
+
 void ApplyCustomParamHandler(HALHANDLE mHalHandle, uint16_t data_len,
                              uint8_t *p_data) {
   STLOG_HAL_D("%s - Enter ", __func__);
@@ -595,8 +917,8 @@
             nciPropSetConfig_CustomField[8] = p_data[6];
             nciPropSetConfig_CustomField[2] = p_data[6] + 6;
             memcpy(nciPropSetConfig_CustomField + 9, p_data + 7, p_data[6]);
-            nciPropSetConfig_CustomField[13] = mFWInfo->uwbFwVersion >> 8;
-            nciPropSetConfig_CustomField[14] = mFWInfo->uwbFwVersion;
+            nciPropSetConfig_CustomField[13] = mFWInfo->chipUwbVersion >> 8;
+            nciPropSetConfig_CustomField[14] = mFWInfo->chipUwbVersion;
 
             if (!HalSendDownstream(mHalHandle, nciPropSetConfig_CustomField,
                                    nciPropSetConfig_CustomField[2] + 3)) {
@@ -697,8 +1019,8 @@
           nciPropSetConfig_CustomField[8] = p_data[6];
           nciPropSetConfig_CustomField[2] = p_data[6] + 6;
           memcpy(nciPropSetConfig_CustomField + 9, p_data + 7, p_data[6]);
-          nciPropSetConfig_CustomField[13] = mFWInfo->uwbVersion >> 8;
-          nciPropSetConfig_CustomField[14] = mFWInfo->uwbVersion;
+          nciPropSetConfig_CustomField[13] = mFWInfo->fileUwbVersion >> 8;
+          nciPropSetConfig_CustomField[14] = mFWInfo->fileUwbVersion;
 
           if (!HalSendDownstream(mHalHandle, nciPropSetConfig_CustomField,
                                  nciPropSetConfig_CustomField[2] + 3)) {
@@ -739,3 +1061,13 @@
   }
   mHalFDState = HAL_FD_STATE_EXIT_APDU;
 }
+
+void SendSwitchToUserMode(HALHANDLE mmHalHandle) {
+  STLOG_HAL_D("%s: enter", __func__);
+
+  if (!HalSendDownstreamTimer(mmHalHandle, ApduSwitchToUser,
+                              sizeof(ApduSwitchToUser), FW_TIMER_DURATION)) {
+    STLOG_HAL_E("%s - SendDownstream failed", __func__);
+  }
+  mHalFD54LState = HAL_FD_ST54L_STATE_SWITCH_TO_USER;
+}
diff --git a/st21nfc/hal/hal_fd.h b/st21nfc/hal/hal_fd.h
index 3ee42e9..44cde09 100644
--- a/st21nfc/hal/hal_fd.h
+++ b/st21nfc/hal/hal_fd.h
@@ -28,14 +28,18 @@
  */
 typedef struct FWInfo {
   uint32_t patchVersion;
-  uint32_t fwVersion;
-  uint8_t hwVersion;
-  uint32_t loaderVersion;
-  uint16_t custVersion;
-  uint16_t confVersion;
-  uint16_t uwbFwVersion;
-  uint16_t uwbVersion;
+  uint32_t chipFwVersion;
+  uint8_t chipHwVersion;
+  uint32_t chipLoaderVersion;
+  uint16_t chipCustVersion;
+  uint16_t chipUwbVersion;
   bool hibernate_exited;
+
+  uint16_t fileUwbVersion;
+  uint8_t fileHwVersion;  // if 0, no FW patch available.
+  uint32_t fileFwVersion;
+  uint16_t fileCustVersion;  // if 0, no custom params available.
+  uint8_t chipProdType;
 } FWInfo;
 
 typedef enum {
@@ -46,6 +50,16 @@
   HAL_FD_STATE_EXIT_APDU,
 } hal_fd_state_e;
 
+typedef enum {
+  HAL_FD_ST54L_STATE_PUY_KEYUSER,
+  HAL_FD_ST54L_STATE_ERASE_UPGRADE_START,
+  HAL_FD_ST54L_STATE_ERASE_NFC_AREA,
+  HAL_FD_ST54L_STATE_ERASE_UPGRADE_STOP,
+  HAL_FD_ST54L_STATE_SEND_RAW_APDU,
+  HAL_FD_ST54L_STATE_SET_CONFIG,
+  HAL_FD_ST54L_STATE_SWITCH_TO_USER,
+} hal_fd_st54l_state_e;
+
 #define FT_CLF_MODE_ERROR 0
 #define FT_CLF_MODE_LOADER 1
 #define FT_CLF_MODE_ROUTER 2
@@ -62,13 +76,18 @@
 
 #define MAX_BUFFER_SIZE 300
 
+// HwVersion :
+#define HW_NFCD 0x04
+#define HW_ST54J 0x05
+#define HW_ST54L 0x06
+
 /* Function declarations */
 int hal_fd_init();
 void hal_fd_close();
 uint8_t ft_cmd_HwReset(uint8_t* pdata, uint8_t* clf_mode);
 void ExitHibernateHandler(HALHANDLE mHalHandle, uint16_t data_len,
                           uint8_t* p_data);
-void UpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t* p_data);
+void FwUpdateHandler(HALHANDLE mHalHandle, uint16_t data_len, uint8_t* p_data);
 void ApplyCustomParamHandler(HALHANDLE mHalHandle, uint16_t data_len,
                              uint8_t* p_data);
 void ApplyUwbParamHandler(HALHANDLE mHalHandle, uint16_t data_len,
diff --git a/st21nfc/hal/halcore.cc b/st21nfc/hal/halcore.cc
index 67ecbf9..d705fd9 100644
--- a/st21nfc/hal/halcore.cc
+++ b/st21nfc/hal/halcore.cc
@@ -95,7 +95,7 @@
             usleep(1000 * (TX_DELAY - delta_time_ms));
         }
         rf_deactivate_delay = false;
-      } else if (data[0] == 0x00 && data[1] == 0x00) {
+      } else if (length > 1 && data[0] == 0x00 && data[1] == 0x00) {
         start_tx_data = HalGetTimestamp();
         rf_deactivate_delay = true;
       } else {
@@ -118,7 +118,8 @@
         STLOG_HAL_W(
             "length is illogical. Header length is %d, packet length %zu\n",
             data[2], length);
-      } else if (rf_deactivate_delay && data[0] == 0x00 && data[1] == 0x00) {
+      } else if (length > 1 && rf_deactivate_delay
+                 && data[0] == 0x00 && data[1] == 0x00) {
         rf_deactivate_delay = false;
       }
 
diff --git a/st21nfc/hal_wrapper.cc b/st21nfc/hal_wrapper.cc
index 5c97179..626f4e1 100644
--- a/st21nfc/hal_wrapper.cc
+++ b/st21nfc/hal_wrapper.cc
@@ -51,6 +51,7 @@
 uint8_t mError_count = 0;
 bool mIsActiveRW = false;
 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mutex_activerw = PTHREAD_MUTEX_INITIALIZER;
 pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
 
 static const uint8_t ApduGetAtr[] = {0x2F, 0x04, 0x05, 0x80,
@@ -213,6 +214,7 @@
       STLOG_HAL_V("%s - mHalWrapperState = HAL_WRAPPER_STATE_OPEN", __func__);
 
       if ((p_data[0] == 0x60) && (p_data[1] == 0x00)) {
+        mIsActiveRW = false;
         mFwUpdateTaskMask = ft_cmd_HwReset(p_data, &mClfMode);
 
         if (mfactoryReset == true) {
@@ -240,12 +242,17 @@
             mHalWrapperCallback(HAL_NFC_OPEN_CPLT_EVT, HAL_NFC_STATUS_FAILED);
             I2cCloseLayer();
           } else {
-            STLOG_HAL_V("%s - Send APDU_GET_ATR_CMD", __func__);
-            mRetryFwDwl--;
-            if (!HalSendDownstreamTimer(mHalHandle, ApduGetAtr,
-                                        sizeof(ApduGetAtr),
-                                        FW_TIMER_DURATION)) {
-              STLOG_HAL_E("%s - SendDownstream failed", __func__);
+            if (((p_data[3] == 0x01) && (p_data[8] == HW_ST54L)) ||
+                ((p_data[2] == 0x41) && (p_data[3] == 0xA2))) {  // ST54L
+              FwUpdateHandler(mHalHandle, data_len, p_data);
+            } else {
+              STLOG_HAL_V("%s - Send APDU_GET_ATR_CMD", __func__);
+              mRetryFwDwl--;
+              if (!HalSendDownstreamTimer(mHalHandle, ApduGetAtr,
+                                          sizeof(ApduGetAtr),
+                                          FW_TIMER_DURATION)) {
+                STLOG_HAL_E("%s - SendDownstream failed", __func__);
+              }
             }
             mHalWrapperState = HAL_WRAPPER_STATE_UPDATE;
           }
@@ -488,11 +495,14 @@
             }
           }
         } else if ((p_data[0] == 0x6f) && (p_data[1] == 0x05)) {
+          (void)pthread_mutex_lock(&mutex_activerw);
           // start timer
           mTimerStarted = true;
           HalSendDownstreamTimer(mHalHandle, 5000);
           mIsActiveRW = true;
+          (void)pthread_mutex_unlock(&mutex_activerw);
         } else if ((p_data[0] == 0x6f) && (p_data[1] == 0x06)) {
+          (void)pthread_mutex_lock(&mutex_activerw);
           // stop timer
           if (mTimerStarted) {
             HalSendDownstreamStopTimer(mHalHandle);
@@ -510,6 +520,7 @@
               HalSendDownstreamTimer(mHalHandle, 1);
             }
           }
+          (void)pthread_mutex_unlock(&mutex_activerw);
         } else if (((p_data[0] == 0x61) && (p_data[1] == 0x05)) ||
                    ((p_data[0] == 0x61) && (p_data[1] == 0x03))) {
           mError_count = 0;
@@ -518,16 +529,33 @@
             HalSendDownstreamStopTimer(mHalHandle);
             mTimerStarted = false;
           }
-        } else if ((p_data[0] == 0x60) && (p_data[1] == 0x07) && (p_data[3] == 0xE1)) {
-          // Core Generic Error - Buffer Overflow Ntf - Restart all
-          STLOG_HAL_E("Core Generic Error - restart");
-          p_data[0] = 0x60;
-          p_data[1] = 0x00;
-          p_data[2] = 0x03;
-          p_data[3] = 0xE1;
-          p_data[4] = 0x00;
-          p_data[5] = 0x00;
-          data_len = 0x6;
+        } else if (data_len >= 4 && p_data[0] == 0x60 && p_data[1] == 0x07) {
+          if (p_data[3] == 0xE1) {
+            // Core Generic Error - Buffer Overflow Ntf - Restart all
+            STLOG_HAL_E("Core Generic Error - restart");
+            p_data[0] = 0x60;
+            p_data[1] = 0x00;
+            p_data[2] = 0x03;
+            p_data[3] = 0xE1;
+            p_data[4] = 0x00;
+            p_data[5] = 0x00;
+            data_len = 0x6;
+          } else if (p_data[3] == 0xE6) {
+            unsigned long hal_ctrl_clk = 0;
+            GetNumValue(NAME_STNFC_CONTROL_CLK, &hal_ctrl_clk,
+                        sizeof(hal_ctrl_clk));
+            if (hal_ctrl_clk) {
+              STLOG_HAL_E("%s - Clock Error - restart", __func__);
+              // Core Generic Error
+              p_data[0] = 0x60;
+              p_data[1] = 0x00;
+              p_data[2] = 0x03;
+              p_data[3] = 0xE6;
+              p_data[4] = 0x00;
+              p_data[5] = 0x00;
+              data_len = 0x6;
+            }
+          }
         }
         mHalWrapperDataCallback(data_len, p_data);
       } else {
@@ -556,7 +584,7 @@
 
     case HAL_WRAPPER_STATE_UPDATE:  // 7
       STLOG_HAL_V("%s - mHalWrapperState = HAL_WRAPPER_STATE_UPDATE", __func__);
-      UpdateHandler(mHalHandle, data_len, p_data);
+      FwUpdateHandler(mHalHandle, data_len, p_data);
       break;
     case HAL_WRAPPER_STATE_APPLY_CUSTOM_PARAM:  // 8
       STLOG_HAL_V(
@@ -570,8 +598,9 @@
       ApplyUwbParamHandler(mHalHandle, data_len, p_data);
       break;
     case HAL_WRAPPER_STATE_SET_ACTIVERW_TIMER:  // 10
+      (void)pthread_mutex_lock(&mutex_activerw);
       if (mIsActiveRW == true) {
-        STLOG_HAL_V(
+        STLOG_HAL_D(
             "%s - mHalWrapperState = "
             "HAL_WRAPPER_STATE_SET_ACTIVERW_TIMER",
             __func__);
@@ -581,6 +610,7 @@
         // Chip state should back to Active
         // at screen off state.
       }
+      (void)pthread_mutex_unlock(&mutex_activerw);
       mHalWrapperState = HAL_WRAPPER_STATE_READY;
       mHalWrapperDataCallback(data_len, p_data);
       break;
diff --git a/st21nfc/include/android_logmsg.h b/st21nfc/include/android_logmsg.h
index 66c05b7..f8a49cf 100644
--- a/st21nfc/include/android_logmsg.h
+++ b/st21nfc/include/android_logmsg.h
@@ -33,6 +33,7 @@
 #define HAL_LOG_TAG "StNfcHal"
 
 extern unsigned char hal_trace_level;
+extern unsigned char hal_conf_trace_level;
 extern int GetNumValue(const char* name, void* p_value, unsigned long len);
 extern int GetByteArrayValue(const char* name, char* pValue, long bufflen,
                              long* len);