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 */