This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit d5f674d96740cd581bf3e062d8ec4a864089f062
Author: Filipe Cavalcanti <filipe.cavalca...@espressif.com>
AuthorDate: Wed Jul 16 12:05:51 2025 -0300

    arch/xtensa: add common driver for E-Fuse on Espressif devices
    
    Adds a common E-Fuse driver to be used by Espressif Xtensa devices.
    
    Signed-off-by: Filipe Cavalcanti <filipe.cavalca...@espressif.com>
---
 arch/xtensa/src/common/espressif/Kconfig     |  44 ++++
 arch/xtensa/src/common/espressif/Make.defs   |   5 +
 arch/xtensa/src/common/espressif/esp_efuse.c | 308 +++++++++++++++++++++++++++
 arch/xtensa/src/common/espressif/esp_efuse.h | 142 ++++++++++++
 4 files changed, 499 insertions(+)

diff --git a/arch/xtensa/src/common/espressif/Kconfig 
b/arch/xtensa/src/common/espressif/Kconfig
index 3f8768777d8..0640638c68f 100644
--- a/arch/xtensa/src/common/espressif/Kconfig
+++ b/arch/xtensa/src/common/espressif/Kconfig
@@ -41,6 +41,50 @@ config ESPRESSIF_ADC_2
 
 endif # ESPRESSIF_ADC
 
+config ESPRESSIF_EFUSE
+       bool "EFUSE support"
+       default n
+       select EFUSE
+       ---help---
+               Enable efuse support.
+
+config ESPRESSIF_EFUSE_VIRTUAL
+       bool "Virtual EFUSE support"
+       depends on ESPRESSIF_EFUSE
+       default n
+       ---help---
+               Enable virtual efuse support to simulate eFuse operations in 
RAM, changes will be reverted each reboot
+
+config ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH
+       bool "Keep E-Fuses in flash"
+       depends on ESPRESSIF_EFUSE_VIRTUAL
+       ---help---
+               In addition to the "Virtual E-Fuses support" option, this 
option just adds
+               a feature to keep E-Fuses after reboots in flash memory.
+
+               During startup, the E-Fuses are copied from flash or,
+               in case if flash is empty, from real E-Fuse to RAM and then 
update flash.
+               This mode is useful when need to keep changes after reboot 
(testing secure_boot,
+               flash_encryption or using MCUBoot + encryption).
+
+if ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH
+
+config ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH_OFFSET
+       hex "E-Fuses offset in flash"
+       depends on ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH
+       default 0x250000
+       ---help---
+               Offset in flash where the E-Fuses will be stored when using the 
"E-Fuses size to keep in flash" option.
+
+config ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH_SIZE
+       hex "E-Fuses size to keep in flash"
+       depends on ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH
+       default 0x2000
+       ---help---
+               Size of E-Fuse region to keep in flash.
+
+endif # ESPRESSIF_EFUSE_VIRTUAL_KEEP_IN_FLASH
+
 config ESPRESSIF_TEMP
        bool "Internal Temperature Sensor"
        default n
diff --git a/arch/xtensa/src/common/espressif/Make.defs 
b/arch/xtensa/src/common/espressif/Make.defs
index e18aeb711a1..03582f9a821 100644
--- a/arch/xtensa/src/common/espressif/Make.defs
+++ b/arch/xtensa/src/common/espressif/Make.defs
@@ -111,6 +111,11 @@ ifeq ($(CONFIG_ESPRESSIF_ADC),y)
 CHIP_CSRCS += esp_adc.c
 endif
 
+ifeq ($(CONFIG_ESPRESSIF_EFUSE),y)
+CHIP_CSRCS += esp_efuse.c
+LDFLAGS    += -u esp_efuse_startup_include_func
+endif
+
 ifeq ($(CONFIG_ESPRESSIF_WIRELESS),y)
 include common$(DELIM)espressif$(DELIM)Wireless.mk
 endif
diff --git a/arch/xtensa/src/common/espressif/esp_efuse.c 
b/arch/xtensa/src/common/espressif/esp_efuse.c
new file mode 100644
index 00000000000..e7066e07460
--- /dev/null
+++ b/arch/xtensa/src/common/espressif/esp_efuse.c
@@ -0,0 +1,308 @@
+/****************************************************************************
+ * arch/xtensa/src/common/espressif/esp_efuse.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include <debug.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/param.h>
+#include <nuttx/irq.h>
+#include <nuttx/efuse/efuse.h>
+
+#include "espressif/esp_efuse.h"
+
+#include "esp_efuse.h"
+#include "esp_efuse_utility.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define EFUSE_MAX_BLK_LEN  256   /* Max length of efuse block. */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct esp_efuse_lowerhalf_s
+{
+  const struct efuse_ops_s *ops; /* Lower half operations */
+  void *upper;                   /* Pointer to efuse_upperhalf_s */
+};
+
+/****************************************************************************
+ * Private Functions Prototypes
+ ****************************************************************************/
+
+/* "Lower half" driver methods */
+
+static int esp_efuse_lowerhalf_read(struct efuse_lowerhalf_s *lower,
+                                    const efuse_desc_t *field[],
+                                    uint8_t *data, size_t bits_len);
+static int esp_efuse_lowerhalf_write(struct efuse_lowerhalf_s *lower,
+                                     const efuse_desc_t *field[],
+                                     const uint8_t *data,
+                                     size_t bits_len);
+static int esp_efuse_lowerhalf_ioctl(struct efuse_lowerhalf_s *lower,
+                                     int cmd, unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* "Lower half" driver methods */
+
+static const struct efuse_ops_s g_esp_efuse_ops =
+{
+  .read_field   = esp_efuse_lowerhalf_read,
+  .write_field  = esp_efuse_lowerhalf_write,
+  .ioctl        = esp_efuse_lowerhalf_ioctl,
+};
+
+/* EFUSE lower-half */
+
+static struct esp_efuse_lowerhalf_s g_esp_efuse_lowerhalf =
+{
+  .ops = &g_esp_efuse_ops,
+  .upper = NULL,
+};
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_efuse_lowerhalf_read
+ *
+ * Description:
+ *   Read value from EFUSE, writing it into an array.
+ *   The field[0]->bit_offset received from the upper half represents
+ *   the bit offset taking into consideration that each block is 256 bits.
+ *   This is necessary as we have multiple blocks of 256 bits.
+ *
+ *   Example: To read data from USER_DATA (EFUSE_BLK3), from bit 16 onwards,
+ *   then bit_offset should be 3*256 + 16.
+ *
+ * Input Parameters:
+ *   lower    - A pointer the publicly visible representation of
+ *              the "lower-half" driver state structure
+ *   field    - A pointer to describing the fields of efuse
+ *   data     - A pointer to array that contains the data for reading
+ *   bits_len - The number of bits required to read
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int esp_efuse_lowerhalf_read(struct efuse_lowerhalf_s *lower,
+                                    const efuse_desc_t *field[],
+                                    uint8_t *data, size_t bits_len)
+{
+  int ret = OK;
+  uint8_t blk_num = field[0]->bit_offset / EFUSE_MAX_BLK_LEN;
+
+  esp_efuse_desc_t recv =
+    {
+      .efuse_block = blk_num,
+      .bit_start = field[0]->bit_offset - blk_num * EFUSE_MAX_BLK_LEN,
+      .bit_count = field[0]->bit_count
+    };
+
+  const esp_efuse_desc_t *desc[] =
+    {
+      &recv,
+      NULL
+    };
+
+  minfo("read from blk_num: %d, bit_start: %d, bit_count: %d\n",
+        blk_num, recv.bit_start, recv.bit_count);
+
+  /* Read the requested field */
+
+  ret = esp_efuse_read_field_blob((const esp_efuse_desc_t**)&desc,
+                                  data,
+                                  bits_len);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_efuse_lowerhalf_write
+ *
+ * Description:
+ *   Write array to EFUSE.
+ *
+ *   The field[0]->bit_offset received from the upper half represents
+ *   the bit offset taking into consideration that each block is 256 bits.
+ *   This is necessary as we have multiple blocks of 256 bits.
+ *
+ *   Example: To write data to USER_DATA (EFUSE_BLK3), from bit 16 onwards,
+ *   then bit_offset should be 3*256 + 16.
+ *
+ * Input Parameters:
+ *   lower    - A pointer the publicly visible representation of
+ *              the "lower-half" driver state structure
+ *   field    - A pointer to describing the fields of efuse
+ *   data     - A pointer to array that contains the data for writing
+ *   bits_len - The number of bits required to write
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int esp_efuse_lowerhalf_write(struct efuse_lowerhalf_s *lower,
+                                     const efuse_desc_t *field[],
+                                     const uint8_t *data,
+                                     size_t bits_len)
+{
+  irqstate_t flags;
+  int ret = OK;
+  uint8_t blk_num = field[0]->bit_offset / EFUSE_MAX_BLK_LEN;
+  esp_efuse_desc_t recv =
+    {
+      .efuse_block = blk_num,
+      .bit_start = field[0]->bit_offset - blk_num * EFUSE_MAX_BLK_LEN,
+      .bit_count = field[0]->bit_count
+    };
+
+  const esp_efuse_desc_t *desc[] =
+    {
+      &recv,
+      NULL
+    };
+
+  minfo("write to blk_num: %d, bit_start: %d, bit_count: %d\n",
+        blk_num, recv.bit_start, recv.bit_count);
+
+  flags = enter_critical_section();
+
+  ret = esp_efuse_write_field_blob((const esp_efuse_desc_t**)&desc,
+                                   data,
+                                   bits_len);
+
+  leave_critical_section(flags);
+
+  if (ret != OK)
+    {
+      return ERROR;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: esp_efuse_lowerhalf_ioctl
+ *
+ * Description:
+ *   Any ioctl commands that are not recognized by the "upper-half"
+ *   driver are forwarded to the lower half driver through this method.
+ *
+ * Input Parameters:
+ *   lower   - A pointer the publicly visible representation of the
+ *             "lower-half" driver state structure.
+ *   cmd     - The ioctl command value
+ *   arg     - The optional argument that accompanies the ioctl command.
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+static int esp_efuse_lowerhalf_ioctl(struct efuse_lowerhalf_s *lower,
+                                     int cmd, unsigned long arg)
+{
+  int ret = OK;
+
+  switch (cmd)
+    {
+      /* We don't have proprietary EFUSE ioctls */
+
+      default:
+        {
+          minfo("Unrecognized cmd: %d\n", cmd);
+          ret = -ENOTTY;
+        }
+        break;
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_efuse_initialize
+ *
+ * Description:
+ *   Initialize the efuse driver. The efuse is initialized
+ *   and registered as 'devpath'
+ *
+ * Input Parameters:
+ *   devpath        - The full path to the efuse device.
+ *                    This should be of the form /dev/efuse
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int esp_efuse_initialize(const char *devpath)
+{
+  struct esp_efuse_lowerhalf_s *lower = NULL;
+  int ret = OK;
+
+  DEBUGASSERT(devpath != NULL);
+
+  lower = &g_esp_efuse_lowerhalf;
+
+  /* Register the efuse upper driver */
+
+  lower->upper = efuse_register(devpath,
+                                (struct efuse_lowerhalf_s *)lower);
+
+  if (lower->upper == NULL)
+    {
+      /* The actual cause of the failure may have been a failure to allocate
+       * perhaps a failure to register the efuse driver (such as if the
+       * 'devpath' were not unique).  We know here but we return EEXIST to
+       * indicate the failure (implying the non-unique devpath).
+       */
+
+      ret = -EEXIST;
+    }
+
+#ifdef CONFIG_ESPRESSIF_EFUSE_VIRTUAL
+  mwarn("Virtual E-Fuses are enabled\n");
+  esp_efuse_utility_update_virt_blocks();
+#endif
+
+  return ret;
+}
diff --git a/arch/xtensa/src/common/espressif/esp_efuse.h 
b/arch/xtensa/src/common/espressif/esp_efuse.h
new file mode 100644
index 00000000000..4d00ae1ac5e
--- /dev/null
+++ b/arch/xtensa/src/common/espressif/esp_efuse.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+ * arch/xtensa/src/common/espressif/esp_efuse.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_EFUSE_H
+#define __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_EFUSE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/efuse/efuse.h>
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ESP_EFUSE_BLK_LEN 256
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* E-Fuse block and bit definitions can be found on the Technical Reference
+ * Manual or on the ESP-IDF documentation.
+ */
+
+#ifdef CONFIG_ARCH_CHIP_ESP32
+typedef enum
+{
+  ESP_EFUSE_BLK0              = 0,
+
+  ESP_EFUSE_BLK1              = 1,
+  ESP_EFUSE_BLK_KEY0          = 1,
+  ESP_EFUSE_BLK_ENCRYPT_FLASH = 1,
+
+  ESP_EFUSE_BLK2              = 2,
+  ESP_EFUSE_BLK_KEY1          = 2,
+  ESP_EFUSE_BLK_SECURE_BOOT   = 2,
+
+  ESP_EFUSE_BLK3              = 3,
+  ESP_EFUSE_BLK_KEY2          = 3,
+  ESP_EFUSE_BLK_KEY_MAX       = 4,
+
+  ESP_EFUSE_BLK_MAX           = 4,
+} esp_efuse_blk_num_t;
+#else
+typedef enum
+{
+  ESP_EFUSE_BLK0                 = 0,
+  ESP_EFUSE_BLK1                 = 1,
+
+  ESP_EFUSE_BLK2                 = 2,
+  ESP_EFUSE_BLK_SYS_DATA_PART1   = 2,
+
+  ESP_EFUSE_BLK3                 = 3,
+  ESP_EFUSE_BLK_USER_DATA        = 3,
+
+  ESP_EFUSE_BLK4                 = 4,
+  ESP_EFUSE_BLK_KEY0             = 4,
+
+  ESP_EFUSE_BLK5                 = 5,
+  ESP_EFUSE_BLK_KEY1             = 5,
+
+  ESP_EFUSE_BLK6                 = 6,
+  ESP_EFUSE_BLK_KEY2             = 6,
+
+  ESP_EFUSE_BLK7                 = 7,
+  ESP_EFUSE_BLK_KEY3             = 7,
+
+  ESP_EFUSE_BLK8                 = 8,
+  ESP_EFUSE_BLK_KEY4             = 8,
+
+  ESP_EFUSE_BLK9                 = 9,
+  ESP_EFUSE_BLK_KEY5             = 9,
+  ESP_EFUSE_BLK_KEY_MAX          = 10,
+
+  ESP_EFUSE_BLK10                = 10,
+  ESP_EFUSE_BLK_SYS_DATA_PART2   = 10,
+
+  ESP_EFUSE_BLK_MAX
+} esp_efuse_blk_num_t;
+#endif
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: esp_efuse_initialize
+ *
+ * Description:
+ *   Initialize the efuse driver. The efuse is initialized
+ *   and registered as 'devpath'
+ *
+ * Input Parameters:
+ *   devpath        - The full path to the efuse device.
+ *                    This should be of the form /dev/efuse
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int esp_efuse_initialize(const char *devpath);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_XTENSA_SRC_COMMON_ESPRESSIF_ESP_EFUSE_H */

Reply via email to