From 693a5c209bb20db0a8721b2a3eacaed8641e98c0 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Mon, 19 Nov 2018 11:46:21 +0800 Subject: [PATCH] efuse: Add API efuse Added support 3/4 coding scheme --- components/efuse/CMakeLists.txt | 54 ++ components/efuse/Kconfig | 37 ++ components/efuse/Makefile.projbuild | 48 ++ components/efuse/component.mk | 10 + components/efuse/efuse_table_gen.py | 415 +++++++++++++ components/efuse/esp32/component.mk | 0 components/efuse/esp32/esp_efuse_table.c | 362 ++++++++++++ components/efuse/esp32/esp_efuse_table.csv | 80 +++ .../efuse/esp32/include/esp_efuse_table.h | 66 +++ components/efuse/esp32/sources.cmake | 1 + components/efuse/include/esp_efuse.h | 294 ++++++++++ components/efuse/src/esp_efuse_api.c | 214 +++++++ components/efuse/src/esp_efuse_fields.c | 117 ++++ components/efuse/src/esp_efuse_utility.c | 512 ++++++++++++++++ components/efuse/src/esp_efuse_utility.h | 140 +++++ components/efuse/test/CMakeLists.txt | 6 + components/efuse/test/component.mk | 6 + components/efuse/test/esp_efuse_test_table.c | 103 ++++ .../efuse/test/esp_efuse_test_table.csv | 33 ++ .../efuse/test/include/esp_efuse_test_table.h | 36 ++ components/efuse/test/test_efuse.c | 546 ++++++++++++++++++ .../efuse/test/test_efuse_coding_scheme.c | 204 +++++++ .../efuse/test_efuse_host/efuse_tests.py | 295 ++++++++++ 23 files changed, 3579 insertions(+) create mode 100644 components/efuse/CMakeLists.txt create mode 100644 components/efuse/Kconfig create mode 100644 components/efuse/Makefile.projbuild create mode 100644 components/efuse/component.mk create mode 100644 components/efuse/efuse_table_gen.py create mode 100644 components/efuse/esp32/component.mk create mode 100644 components/efuse/esp32/esp_efuse_table.c create mode 100644 components/efuse/esp32/esp_efuse_table.csv create mode 100644 components/efuse/esp32/include/esp_efuse_table.h create mode 100644 components/efuse/esp32/sources.cmake create mode 100644 components/efuse/include/esp_efuse.h create mode 100644 components/efuse/src/esp_efuse_api.c create mode 100644 components/efuse/src/esp_efuse_fields.c create mode 100644 components/efuse/src/esp_efuse_utility.c create mode 100644 components/efuse/src/esp_efuse_utility.h create mode 100644 components/efuse/test/CMakeLists.txt create mode 100644 components/efuse/test/component.mk create mode 100644 components/efuse/test/esp_efuse_test_table.c create mode 100644 components/efuse/test/esp_efuse_test_table.csv create mode 100644 components/efuse/test/include/esp_efuse_test_table.h create mode 100644 components/efuse/test/test_efuse.c create mode 100644 components/efuse/test/test_efuse_coding_scheme.c create mode 100644 components/efuse/test_efuse_host/efuse_tests.py diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt new file mode 100644 index 000000000..e11e1e74f --- /dev/null +++ b/components/efuse/CMakeLists.txt @@ -0,0 +1,54 @@ +set(SOC_NAME ${IDF_TARGET}) + +if(EXISTS "${COMPONENT_PATH}/${SOC_NAME}") + include(${COMPONENT_PATH}/${SOC_NAME}/sources.cmake) + spaces2list(EFUSE_SOC_SRCS) + add_prefix(COMPONENT_SRCS "${SOC_NAME}/" ${EFUSE_SOC_SRCS}) + set(COMPONENT_ADD_INCLUDEDIRS include + ${SOC_NAME}/include) +endif() + +list(APPEND COMPONENT_SRCS "src/esp_efuse_api.c" + "src/esp_efuse_fields.c" + "src/esp_efuse_utility.c") + +set(COMPONENT_REQUIRES) +set(COMPONENT_PRIV_REQUIRES bootloader_support) +register_component() + + +################### +# Make common files esp_efuse_table.c and include/esp_efuse_table.h files. +# The generated files are used in the bootloader and application space. +# To generate new *.c/*.h files run the command manually "make efuse_common_table". +set(EFUSE_COMMON_TABLE_CSV_PATH "${COMPONENT_PATH}/${SOC_NAME}/esp_efuse_table.csv") +add_custom_target(efuse_common_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_COMMON_TABLE_CSV_PATH}) + + +# custom gen header files +if(${CONFIG_EFUSE_CUSTOM_TABLE}) + # Custom filename expands any path relative to the project + get_filename_component(EFUSE_CUSTOM_TABLE_CSV_PATH "${CONFIG_EFUSE_CUSTOM_TABLE_FILENAME}" ABSOLUTE BASE_DIR "${PROJECT_PATH}") + + add_custom_target(efuse_custom_table ALL + COMMAND ${CMAKE_COMMAND} -E echo "Efuse CSV ${EFUSE_CUSTOM_TABLE_CSV_PATH} does not exist. Either change efuse table file in menuconfig or create this input file." + COMMAND ${CMAKE_COMMAND} -E touch "${CMAKE_BINARY_DIR}/CMakeCache.txt" + COMMAND ${CMAKE_COMMAND} -P ${IDF_PATH}/tools/cmake/scripts/fail.cmake) + +string(REPLACE ".csv" ".c" HEADER_CUSTOM ${EFUSE_CUSTOM_TABLE_CSV_PATH}) +add_custom_command(OUTPUT ${HEADER_CUSTOM} + COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" + ${EFUSE_COMMON_TABLE_CSV_PATH} ${EFUSE_CUSTOM_TABLE_CSV_PATH} + DEPENDS ${EFUSE_CUSTOM_TABLE_CSV_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" + VERBATIM) + +if(EXISTS ${EFUSE_CUSTOM_TABLE_CSV_PATH}) + add_custom_target(efuse_custom_table ALL DEPENDS ${HEADER_CUSTOM} ${EFUSE_CUSTOM_TABLE_CSV_PATH}) +endif() + +endif()#if(${CONFIG_EFUSE_CUSTOM_TABLE}) + +################### +# Generates files for unit test. This command is run manually. +set(EFUSE_TEST_TABLE_CSV_PATH "${COMPONENT_PATH}/test/esp_efuse_test_table.csv") +add_custom_target(efuse_test_table COMMAND "${PYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/efuse_table_gen.py" ${EFUSE_TEST_TABLE_CSV_PATH}) diff --git a/components/efuse/Kconfig b/components/efuse/Kconfig new file mode 100644 index 000000000..d07ae851f --- /dev/null +++ b/components/efuse/Kconfig @@ -0,0 +1,37 @@ +menu "eFuse bit Manager" + +config EFUSE_CUSTOM_TABLE + bool "Use custom eFuse table" + default n + help + Allows to generate a structure for eFuse from the CSV file. + +config EFUSE_CUSTOM_TABLE_FILENAME + string "Custom eFuse CSV file" if EFUSE_CUSTOM_TABLE + default main/esp_efuse_custom_table.csv + help + Name of the custom eFuse CSV filename. This path is evaluated + relative to the project root directory. + +config EFUSE_VIRTUAL + bool "Emulate eFuse work" + default n + help + If this option is set, all permanent changes (via eFuse) are disabled. + Log output will state changes which would be applied, but they will not be. + +choice EFUSE_CODE_SCHEME + prompt "eFuse Code Scheme" + default EFUSE_CODE_SCHEME_NONE + help + Selector eFuse code scheme. + +config EFUSE_CODE_SCHEME_NONE + bool "None" +config EFUSE_CODE_SCHEME_3_4 + bool "3/4" +config EFUSE_CODE_SCHEME_REPEAT + bool "Repeat" +endchoice + +endmenu diff --git a/components/efuse/Makefile.projbuild b/components/efuse/Makefile.projbuild new file mode 100644 index 000000000..35e0355a9 --- /dev/null +++ b/components/efuse/Makefile.projbuild @@ -0,0 +1,48 @@ +# +# eFuse Manager ganeretes header file. +# +# .PHONY: efuse_table efuse_custom_table efuse_common_table efuse_test_table show_efuse_table + +GEN_EFUSE_TABLE := $(PYTHON) $(COMPONENT_PATH)/efuse_table_gen.py + +efuse_table: efuse_custom_table + +################### +# Make common files esp_efuse_table.c and include/esp_efuse_table.h files. +# The generated files are used in the bootloader and application space. +# To generate new *.c/*.h files run the command manually "make efuse_common_table". +SOC_NAME := $(IDF_TARGET) +EFUSE_COMMON_TABLE_CSV_PATH := $(COMPONENT_PATH)/$(SOC_NAME)/esp_efuse_table.csv +efuse_common_table: + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) + +################### +# Make custom files +# Changes in esp_efuse_custom_table.csv file lead to regeneration of esp_efuse_custom_table.c and include/esp_efuse_custom_table.h files. +# The generated files are used only in the application. +ifdef IS_BOOTLOADER_BUILD +efuse_custom_table: +else + +ifdef CONFIG_EFUSE_CUSTOM_TABLE +# Path to CSV file is relative to project path for custom CSV files. +EFUSE_CUSTOM_TABLE_CSV_PATH := $(call dequote,$(abspath $(call dequote, $(PROJECT_PATH))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) +EFUSE_CUSTOM_TABLE_OUT_PATH := $(call dequote,$(abspath $(call dequote, $(BUILD_DIR_BASE))/$(call dequote,$(CONFIG_EFUSE_CUSTOM_TABLE_FILENAME)))) +efuse_custom_table: $(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o) + +$(EFUSE_CUSTOM_TABLE_OUT_PATH:.csv=.o): $(EFUSE_CUSTOM_TABLE_CSV_PATH) + @echo "$(EFUSE_CUSTOM_TABLE_OUT_PATH)" + @echo "$(EFUSE_CUSTOM_TABLE_CSV_PATH)" + $(GEN_EFUSE_TABLE) $(EFUSE_COMMON_TABLE_CSV_PATH) $(EFUSE_CUSTOM_TABLE_CSV_PATH) + +else +efuse_custom_table: +endif + +endif + +################### +# Generates files for unit test. This command is run manually. +EFUSE_TEST_TABLE_CSV_PATH := $(COMPONENT_PATH)/test/esp_efuse_test_table.csv +efuse_test_table: + $(GEN_EFUSE_TABLE) $(EFUSE_TEST_TABLE_CSV_PATH) diff --git a/components/efuse/component.mk b/components/efuse/component.mk new file mode 100644 index 000000000..393f21020 --- /dev/null +++ b/components/efuse/component.mk @@ -0,0 +1,10 @@ +# +# Component Makefile +# currently the only SoC supported; to be moved into Kconfig +SOC_NAME := $(IDF_TARGET) + +COMPONENT_SRCDIRS := $(SOC_NAME) src + +COMPONENT_ADD_INCLUDEDIRS := $(SOC_NAME)/include include + +-include $(COMPONENT_PATH)/$(SOC_NAME)/component.mk \ No newline at end of file diff --git a/components/efuse/efuse_table_gen.py b/components/efuse/efuse_table_gen.py new file mode 100644 index 000000000..a64f2f949 --- /dev/null +++ b/components/efuse/efuse_table_gen.py @@ -0,0 +1,415 @@ +#!/usr/bin/env python +# +# ESP32 efuse table generation tool +# +# Converts efuse table to header file efuse_table.h. +# +# Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +# +# 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. +from __future__ import print_function, division +import argparse +import os +import re +import struct +import sys +import hashlib +import binascii +import ntpath + +__version__ = '1.0' + +quiet = False + +copyright = '''// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 +''' + +def status(msg): + """ Print status message to stderr """ + if not quiet: + critical(msg) + +def critical(msg): + """ Print critical message to stderr """ + sys.stderr.write(msg) + sys.stderr.write('\n') + +class FuseTable(list): + def __init__(self): + super(FuseTable, self).__init__(self) + self.md5_digest = "" + + @classmethod + def from_csv(cls, csv_contents): + res = FuseTable() + res.md5_digest = res.calc_md5(csv_contents) + lines = csv_contents.splitlines() + def expand_vars(f): + f = os.path.expandvars(f) + m = re.match(r'(? 1 ) + if len(duplicates) != 0: + i_count = 0 + for p in res: + if len(duplicates.intersection([p.field_name])) != 0: + p.group = str(i_count) + i_count += 1 + else: + i_count = 0 + res.verify_duplicate_name() + + return res + + def verify_duplicate_name(self): + # check on duplicate name + names = [ p.field_name for p in self ] + duplicates = set( n for n in names if names.count(n) > 1 ) + + # print sorted duplicate partitions by name + if len(duplicates) != 0: + fl_error = False + for p in self: + field_name = p.field_name + p.group + if field_name != "" and len(duplicates.intersection([field_name])) != 0: + fl_error = True + print ("Field at %s, %s, %s, %s have dublicate field_name" + % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count)) + if fl_error == True: + raise InputError("Field names must be unique") + + def verify(self): + + '''list_field_names = []''' + for p in self: + p.verify() + + self.verify_duplicate_name() + + # check for overlaps + last = None + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + if last is not None and last.efuse_block == p.efuse_block and p.bit_start < last.bit_start + last.bit_count: + raise InputError("Field at %s, %s, %s, %s overlaps %s, %s, %s, %s" + % ( p.field_name, p.efuse_block, p.bit_start, p.bit_count, + last.field_name, last.efuse_block, last.bit_start, last.bit_count)) + last = p + + def calc_md5(self, csv_contents): + return hashlib.md5(csv_contents).hexdigest() + + def show_range_used_bits(self): + # print used and free bits + rows = '' + rows += 'Sorted efuse table:\n' + num = 1 + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + rows += "#%d \t%s \t\t%s \t\t%d \t\t%d" % (num, p.field_name, p.efuse_block, p.bit_start, p.bit_count) + "\n" + num += 1 + + rows += '\nUsed bits in efuse table:\n' + last = None + for p in sorted(self, key=lambda x:(x.efuse_block, x.bit_start)): + if last is None: + rows += '%s \n[%d ' % (p.efuse_block, p.bit_start) + if last is not None: + if last.efuse_block != p.efuse_block: + rows += '%d] \n\n%s \n[%d ' % (last.bit_start + last.bit_count - 1, p.efuse_block, p.bit_start) + elif last.bit_start + last.bit_count != p.bit_start: + rows += '%d] [%d ' % (last.bit_start + last.bit_count - 1, p.bit_start) + last = p + rows += '%d] \n' % (last.bit_start + last.bit_count - 1) + rows += '\nNote: Not printed ranges are free for using.\n' + return rows + + def to_header(self, file_name): + rows = [ copyright ] + rows += [ "#ifdef __cplusplus", + 'extern "C" {', + "#endif", + "", + "", + "// md5_digest " + self.md5_digest, + "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", + "// To show efuse_table run the command 'make show_efuse_table'.", + "", + ""] + + last_field_name = '' + for p in self: + if (p.field_name != last_field_name): + rows += [ "extern const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[];" ] + last_field_name = p.field_name + + rows += [ "", + "#ifdef __cplusplus", + "}", + "#endif", + ""] + return '\n'.join(rows) + "\n" + + def to_c_file(self, file_name, debug): + rows = [ copyright ] + rows += [ '#include "esp_efuse.h"', + '#include "' + file_name + '.h"', + "", + "// md5_digest " + self.md5_digest, + "// This file was generated automatically from the file " + file_name + ".csv. DO NOT CHANGE THIS FILE MANUALLY.", + "// If you want to change some fields, you need to change " + file_name + ".csv file then build system will generate this header file", + "// To show efuse_table run the command 'make show_efuse_table'.", + "", + ""] + + last_name = '' + for p in self: + if (p.field_name != last_name): + if last_name != '': + rows += [ "};\n"] + rows += [ "static const esp_efuse_desc_t " + p.field_name + "[] = {" ] + last_name = p.field_name + rows += [ p.to_struct(debug) + "," ] + rows += [ "};\n" ] + + rows += ["\n\n\n"] + + last_name = '' + for p in self: + if (p.field_name != last_name): + if last_name != '': + rows += [" NULL", + "};\n" ] + rows += [ "const esp_efuse_desc_t* " + "ESP_EFUSE_" + p.field_name + "[] = {" ] + last_name = p.field_name + index = str(0) if str(p.group) == "" else str(p.group) + rows += [ " &" + p.field_name + "[" + index + "], \t\t// " + p.comment ] + rows += [" NULL", + "};\n" ] + + return '\n'.join(rows) + "\n" + +class FuseDefinition(object): + + def __init__(self): + self.field_name = "" + self.group = "" + self.efuse_block = "" + self.bit_start = None + self.bit_count = None + self.comment = "" + + @classmethod + def from_csv(cls, line): + """ Parse a line from the CSV """ + line_w_defaults = line + ",,,," # lazy way to support default fields + fields = [ f.strip() for f in line_w_defaults.split(",") ] + + res = FuseDefinition() + res.field_name = fields[0] + res.efuse_block = res.parse_block(fields[1]) + res.bit_start = res.parse_num(fields[2]) + res.bit_count = res.parse_num(fields[3]) + if res.bit_count is None or res.bit_count == 0: + raise InputError("Field bit_count can't be empty") + res.comment = fields[4] + return res + + def parse_num(self, strval): + if strval == "": + return None # Field will fill in default + return self.parse_int(strval) + + def parse_int(self, v): + try: + return int(v, 0) + except ValueError: + raise InputError("Invalid field value %s" % v) + + def parse_block(self, strval): + if strval == "": + raise InputError("Field 'efuse_block' can't be left empty.") + if strval != "EFUSE_BLK0" and strval != "EFUSE_BLK1" and strval != "EFUSE_BLK2" and strval != "EFUSE_BLK3": + raise InputError("Field 'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3") + return strval + + def verify(self): + '''if self.field_name is None: + raise ValidationError(self, "field_name field is not set")''' + if self.efuse_block is None: + raise ValidationError(self, "efuse_block field is not set") + if self.bit_count is None: + raise ValidationError(self, "bit_count field is not set") + + max_bits = 256 + if self.efuse_block == "EFUSE_BLK0": + max_bits = 224 + if self.bit_start + self.bit_count > max_bits: + raise ValidationError(self, "The field is outside the boundaries of the %s block" % (self.efuse_block)) + + def get_full_name(self): + def get_postfix(group): + postfix = "" + if group != "": + postfix = "_PART_" + group + return postfix + + return self.field_name + get_postfix(self.group) + + def to_struct(self, debug): + start = " {" + if (debug == True): + start = " {" + '"' + self.field_name + '" ,' + return ", ".join([start + self.efuse_block, + str(self.bit_start), + str(self.bit_count) + "}, \t // " + self.comment]) + +def process_input_file(file): + status("Parsing efuse CSV input file " + file.name + " ...") + input = file.read() + table = FuseTable.from_csv(input) + + status("Verifying efuse table...") + table.verify() + return table + +def create_output_files(name, output_table, debug): + file_name = os.path.splitext(os.path.basename(name))[0] + gen_dir = os.path.dirname(name) + + dir_for_file_h = gen_dir + "/include" + try: + os.stat(dir_for_file_h) + except: + os.mkdir(dir_for_file_h) + + file_h_path = os.path.join(dir_for_file_h, file_name + ".h") + file_c_path = os.path.join(gen_dir, file_name + ".c") + + status("Creating efuse *.h file " + file_h_path + " ...") + output = output_table.to_header(file_name) + with open(file_h_path, 'w') as f: + f.write(output) + f.close() + + status("Creating efuse *.c file " + file_c_path + " ...") + output = output_table.to_c_file(file_name, debug) + with open(file_c_path, 'w') as f: + f.write(output) + f.close() + +def main(): + global quiet + + parser = argparse.ArgumentParser(description='ESP32 eFuse Manager') + + parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true') + parser.add_argument('--debug', help='Create header file with debug info', default=False, action="store_false") + parser.add_argument('--info', help='Print info about range of used bits', default=False, action="store_true") + parser.add_argument('common_input', help='Path to common CSV file to parse.', type=argparse.FileType('rb')) + parser.add_argument('custom_input', help='Path to custom CSV file to parse.', type=argparse.FileType('rb'), nargs='?', default=None) + + args = parser.parse_args() + + quiet = args.quiet + debug = args.debug + info = args.info + + common_table = process_input_file(args.common_input) + if args.custom_input is not None: + custom_table = process_input_file(args.custom_input) + common_table += custom_table + common_table.verify() + if info == True: + output_table = common_table + else: + output_table = custom_table + name = args.custom_input.name + else: + output_table = common_table + name = args.common_input.name + output_table.verify() + + # save files. + if info == False: + create_output_files(name, output_table, debug) + else: + print(output_table.show_range_used_bits()) + + return 0 + +class InputError(RuntimeError): + def __init__(self, e): + super(InputError, self).__init__(e) + +class ValidationError(InputError): + def __init__(self, p, message): + super(ValidationError, self).__init__( + "Entry %s invalid: %s" % (p.field_name, message)) + +if __name__ == '__main__': + try: + main() + except InputError as e: + print(e, file=sys.stderr) + sys.exit(2) diff --git a/components/efuse/esp32/component.mk b/components/efuse/esp32/component.mk new file mode 100644 index 000000000..e69de29bb diff --git a/components/efuse/esp32/esp_efuse_table.c b/components/efuse/esp32/esp_efuse_table.c new file mode 100644 index 000000000..69685c0e8 --- /dev/null +++ b/components/efuse/esp32/esp_efuse_table.c @@ -0,0 +1,362 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_efuse.h" +#include "esp_efuse_table.h" + + +// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +static const esp_efuse_desc_t MAC_FACTORY[] = { + {EFUSE_BLK0, 72, 8}, // Factory MAC addr [0], + {EFUSE_BLK0, 64, 8}, // Factory MAC addr [1], + {EFUSE_BLK0, 56, 8}, // Factory MAC addr [2], + {EFUSE_BLK0, 48, 8}, // Factory MAC addr [3], + {EFUSE_BLK0, 40, 8}, // Factory MAC addr [4], + {EFUSE_BLK0, 32, 8}, // Factory MAC addr [5], +}; + +static const esp_efuse_desc_t MAC_FACTORY_CRC[] = { + {EFUSE_BLK0, 80, 8}, // CRC8 for factory MAC address, +}; + +static const esp_efuse_desc_t MAC_CUSTOM_CRC[] = { + {EFUSE_BLK3, 0, 8}, // CRC8 for custom MAC address., +}; + +static const esp_efuse_desc_t MAC_CUSTOM[] = { + {EFUSE_BLK3, 8, 48}, // Custom MAC, +}; + +static const esp_efuse_desc_t MAC_CUSTOM_VER[] = { + {EFUSE_BLK3, 184, 8}, // Custom MAC version, +}; + +static const esp_efuse_desc_t SECURE_BOOT_KEY[] = { + {EFUSE_BLK2, 0, 256}, // Security boot. Key., +}; + +static const esp_efuse_desc_t ABS_DONE_0[] = { + {EFUSE_BLK0, 196, 1}, // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0, +}; + +static const esp_efuse_desc_t ENCRYPT_FLASH_KEY[] = { + {EFUSE_BLK1, 0, 256}, // Flash encrypt. Key., +}; + +static const esp_efuse_desc_t ENCRYPT_CONFIG[] = { + {EFUSE_BLK0, 188, 4}, // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M, +}; + +static const esp_efuse_desc_t DISABLE_DL_ENCRYPT[] = { + {EFUSE_BLK0, 199, 1}, // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT., +}; + +static const esp_efuse_desc_t DISABLE_DL_DECRYPT[] = { + {EFUSE_BLK0, 200, 1}, // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT., +}; + +static const esp_efuse_desc_t DISABLE_DL_CACHE[] = { + {EFUSE_BLK0, 201, 1}, // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE., +}; + +static const esp_efuse_desc_t DISABLE_JTAG[] = { + {EFUSE_BLK0, 198, 1}, // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG., +}; + +static const esp_efuse_desc_t CONSOLE_DEBUG_DISABLE[] = { + {EFUSE_BLK0, 194, 1}, // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE., +}; + +static const esp_efuse_desc_t FLASH_CRYPT_CNT[] = { + {EFUSE_BLK0, 20, 8}, // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT., +}; + +static const esp_efuse_desc_t WR_DIS_FLASH_CRYPT_CNT[] = { + {EFUSE_BLK0, 2, 1}, // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT, +}; + +static const esp_efuse_desc_t WR_DIS_BLK1[] = { + {EFUSE_BLK0, 7, 1}, // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1, +}; + +static const esp_efuse_desc_t WR_DIS_BLK2[] = { + {EFUSE_BLK0, 8, 1}, // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2, +}; + +static const esp_efuse_desc_t WR_DIS_BLK3[] = { + {EFUSE_BLK0, 9, 1}, // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3, +}; + +static const esp_efuse_desc_t RD_DIS_BLK1[] = { + {EFUSE_BLK0, 16, 1}, // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1, +}; + +static const esp_efuse_desc_t RD_DIS_BLK2[] = { + {EFUSE_BLK0, 17, 1}, // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2, +}; + +static const esp_efuse_desc_t RD_DIS_BLK3[] = { + {EFUSE_BLK0, 18, 1}, // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3, +}; + +static const esp_efuse_desc_t CHIP_VER_DIS_APP_CPU[] = { + {EFUSE_BLK0, 96, 1}, // EFUSE_RD_CHIP_VER_DIS_APP_CPU, +}; + +static const esp_efuse_desc_t CHIP_VER_DIS_BT[] = { + {EFUSE_BLK0, 97, 1}, // EFUSE_RD_CHIP_VER_DIS_BT, +}; + +static const esp_efuse_desc_t CHIP_VER_PKG[] = { + {EFUSE_BLK0, 105, 3}, // EFUSE_RD_CHIP_VER_PKG, +}; + +static const esp_efuse_desc_t CHIP_CPU_FREQ_LOW[] = { + {EFUSE_BLK0, 108, 1}, // EFUSE_RD_CHIP_CPU_FREQ_LOW, +}; + +static const esp_efuse_desc_t CHIP_CPU_FREQ_RATED[] = { + {EFUSE_BLK0, 109, 1}, // EFUSE_RD_CHIP_CPU_FREQ_RATED, +}; + +static const esp_efuse_desc_t CHIP_VER_REV1[] = { + {EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1, +}; + +static const esp_efuse_desc_t XPD_SDIO_REG[] = { + {EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG, +}; + +static const esp_efuse_desc_t SDIO_TIEH[] = { + {EFUSE_BLK0, 143, 1}, // EFUSE_RD_SDIO_TIEH, +}; + +static const esp_efuse_desc_t SDIO_FORCE[] = { + {EFUSE_BLK0, 144, 1}, // EFUSE_RD_SDIO_FORCE, +}; + +static const esp_efuse_desc_t ADC_VREF_AND_SDIO_DREF[] = { + {EFUSE_BLK0, 136, 6}, // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1], +}; + +static const esp_efuse_desc_t ADC1_TP_LOW[] = { + {EFUSE_BLK3, 96, 7}, // TP_REG EFUSE_RD_ADC1_TP_LOW, +}; + +static const esp_efuse_desc_t ADC2_TP_LOW[] = { + {EFUSE_BLK3, 112, 7}, // TP_REG EFUSE_RD_ADC2_TP_LOW, +}; + +static const esp_efuse_desc_t ADC1_TP_HIGH[] = { + {EFUSE_BLK3, 103, 9}, // TP_REG EFUSE_RD_ADC1_TP_HIGH, +}; + +static const esp_efuse_desc_t ADC2_TP_HIGH[] = { + {EFUSE_BLK3, 119, 9}, // TP_REG EFUSE_RD_ADC2_TP_HIGH, +}; + + + + + +const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[] = { + &MAC_FACTORY[0], // Factory MAC addr [0] + &MAC_FACTORY[1], // Factory MAC addr [1] + &MAC_FACTORY[2], // Factory MAC addr [2] + &MAC_FACTORY[3], // Factory MAC addr [3] + &MAC_FACTORY[4], // Factory MAC addr [4] + &MAC_FACTORY[5], // Factory MAC addr [5] + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[] = { + &MAC_FACTORY_CRC[0], // CRC8 for factory MAC address + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[] = { + &MAC_CUSTOM_CRC[0], // CRC8 for custom MAC address. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[] = { + &MAC_CUSTOM[0], // Custom MAC + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[] = { + &MAC_CUSTOM_VER[0], // Custom MAC version + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[] = { + &SECURE_BOOT_KEY[0], // Security boot. Key. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[] = { + &ABS_DONE_0[0], // Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[] = { + &ENCRYPT_FLASH_KEY[0], // Flash encrypt. Key. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[] = { + &ENCRYPT_CONFIG[0], // Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[] = { + &DISABLE_DL_ENCRYPT[0], // Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[] = { + &DISABLE_DL_DECRYPT[0], // Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[] = { + &DISABLE_DL_CACHE[0], // Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[] = { + &DISABLE_JTAG[0], // Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[] = { + &CONSOLE_DEBUG_DISABLE[0], // Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[] = { + &FLASH_CRYPT_CNT[0], // Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[] = { + &WR_DIS_FLASH_CRYPT_CNT[0], // Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[] = { + &WR_DIS_BLK1[0], // Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[] = { + &WR_DIS_BLK2[0], // Security boot. Write protection security key. EFUSE_WR_DIS_BLK2 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[] = { + &WR_DIS_BLK3[0], // Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[] = { + &RD_DIS_BLK1[0], // Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[] = { + &RD_DIS_BLK2[0], // Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[] = { + &RD_DIS_BLK3[0], // Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[] = { + &CHIP_VER_DIS_APP_CPU[0], // EFUSE_RD_CHIP_VER_DIS_APP_CPU + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[] = { + &CHIP_VER_DIS_BT[0], // EFUSE_RD_CHIP_VER_DIS_BT + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[] = { + &CHIP_VER_PKG[0], // EFUSE_RD_CHIP_VER_PKG + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[] = { + &CHIP_CPU_FREQ_LOW[0], // EFUSE_RD_CHIP_CPU_FREQ_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[] = { + &CHIP_CPU_FREQ_RATED[0], // EFUSE_RD_CHIP_CPU_FREQ_RATED + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = { + &CHIP_VER_REV1[0], // EFUSE_RD_CHIP_VER_REV1 + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = { + &XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[] = { + &SDIO_TIEH[0], // EFUSE_RD_SDIO_TIEH + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[] = { + &SDIO_FORCE[0], // EFUSE_RD_SDIO_FORCE + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[] = { + &ADC_VREF_AND_SDIO_DREF[0], // EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1] + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[] = { + &ADC1_TP_LOW[0], // TP_REG EFUSE_RD_ADC1_TP_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[] = { + &ADC2_TP_LOW[0], // TP_REG EFUSE_RD_ADC2_TP_LOW + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[] = { + &ADC1_TP_HIGH[0], // TP_REG EFUSE_RD_ADC1_TP_HIGH + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[] = { + &ADC2_TP_HIGH[0], // TP_REG EFUSE_RD_ADC2_TP_HIGH + NULL +}; + diff --git a/components/efuse/esp32/esp_efuse_table.csv b/components/efuse/esp32/esp_efuse_table.csv new file mode 100644 index 000000000..8c6db79dd --- /dev/null +++ b/components/efuse/esp32/esp_efuse_table.csv @@ -0,0 +1,80 @@ +# field_name, | efuse_block, | bit_start, | bit_count, |comment # +# | (EFUSE_BLK0 | (0..255) | (1..256) | # +# | EFUSE_BLK1 | | | # +# | EFUSE_BLK2 | | | # +# | EFUSE_BLK3) | | | # +########################################################################## +# !!!!!!!!!!! # +# After editing this file, run the command manually "make efuse_common_table" or "idf.py efuse_common_table" +# this will generate new source files, next rebuild all the sources. +# !!!!!!!!!!! # + +# Factory MAC address # +####################### +MAC_FACTORY, EFUSE_BLK0, 72, 8, Factory MAC addr [0] +, EFUSE_BLK0, 64, 8, Factory MAC addr [1] +, EFUSE_BLK0, 56, 8, Factory MAC addr [2] +, EFUSE_BLK0, 48, 8, Factory MAC addr [3] +, EFUSE_BLK0, 40, 8, Factory MAC addr [4] +, EFUSE_BLK0, 32, 8, Factory MAC addr [5] +MAC_FACTORY_CRC, EFUSE_BLK0, 80, 8, CRC8 for factory MAC address + +# Custom MAC address # +###################### +MAC_CUSTOM_CRC, EFUSE_BLK3, 0, 8, CRC8 for custom MAC address. +MAC_CUSTOM, EFUSE_BLK3, 8, 48, Custom MAC +MAC_CUSTOM_VER, EFUSE_BLK3, 184, 8, Custom MAC version + +# Security boot # +################# +SECURE_BOOT_KEY, EFUSE_BLK2, 0, 256, Security boot. Key. +ABS_DONE_0, EFUSE_BLK0, 196, 1, Secure boot is enabled for bootloader image. EFUSE_RD_ABS_DONE_0 + +# Flash encrypt # +################# +ENCRYPT_FLASH_KEY, EFUSE_BLK1, 0, 256, Flash encrypt. Key. +ENCRYPT_CONFIG, EFUSE_BLK0, 188, 4, Flash encrypt. EFUSE_FLASH_CRYPT_CONFIG_M + +DISABLE_DL_ENCRYPT, EFUSE_BLK0, 199, 1, Flash encrypt. Disable UART bootloader encryption. EFUSE_DISABLE_DL_ENCRYPT. +DISABLE_DL_DECRYPT, EFUSE_BLK0, 200, 1, Flash encrypt. Disable UART bootloader decryption. EFUSE_DISABLE_DL_DECRYPT. +DISABLE_DL_CACHE, EFUSE_BLK0, 201, 1, Flash encrypt. Disable UART bootloader MMU cache. EFUSE_DISABLE_DL_CACHE. +DISABLE_JTAG, EFUSE_BLK0, 198, 1, Flash encrypt. Disable JTAG. EFUSE_RD_DISABLE_JTAG. +CONSOLE_DEBUG_DISABLE, EFUSE_BLK0, 194, 1, Flash encrypt. Disable ROM BASIC interpreter fallback. EFUSE_RD_CONSOLE_DEBUG_DISABLE. +FLASH_CRYPT_CNT, EFUSE_BLK0, 20, 8, Flash encrypt. Flash encryption is enabled if this field has an odd number of bits set. EFUSE_FLASH_CRYPT_CNT. + +# Write protection # +#################### +WR_DIS_FLASH_CRYPT_CNT, EFUSE_BLK0, 2, 1, Flash encrypt. Write protection FLASH_CRYPT_CNT. EFUSE_WR_DIS_FLASH_CRYPT_CNT +WR_DIS_BLK1, EFUSE_BLK0, 7, 1, Flash encrypt. Write protection encryption key. EFUSE_WR_DIS_BLK1 +WR_DIS_BLK2, EFUSE_BLK0, 8, 1, Security boot. Write protection security key. EFUSE_WR_DIS_BLK2 +WR_DIS_BLK3, EFUSE_BLK0, 9, 1, Write protection for EFUSE_BLK3. EFUSE_WR_DIS_BLK3 + +# Read protection # +################### +RD_DIS_BLK1, EFUSE_BLK0, 16, 1, Flash encrypt. efuse_key_read_protected. EFUSE_RD_DIS_BLK1 +RD_DIS_BLK2, EFUSE_BLK0, 17, 1, Security boot. efuse_key_read_protected. EFUSE_RD_DIS_BLK2 +RD_DIS_BLK3, EFUSE_BLK0, 18, 1, Read protection for EFUSE_BLK3. EFUSE_RD_DIS_BLK3 + +# Chip info # +############# +CHIP_VER_DIS_APP_CPU, EFUSE_BLK0, 96, 1, EFUSE_RD_CHIP_VER_DIS_APP_CPU +CHIP_VER_DIS_BT, EFUSE_BLK0, 97, 1, EFUSE_RD_CHIP_VER_DIS_BT +CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG +CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW +CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED +CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1 +XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG +SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH +SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE + +#SDIO_DREFH, EFUSE_BLK0, 136, 2, EFUSE_RD_SDIO_DREFH +#SDIO_DREFM, EFUSE_BLK0, 138, 2, EFUSE_RD_SDIO_DREFM +#SDIO_DREFL, EFUSE_BLK0, 140, 2, EFUSE_RD_SDIO_DREFL + +# esp_adc_cal # +############### +ADC_VREF_AND_SDIO_DREF, EFUSE_BLK0, 136, 6, EFUSE_RD_ADC_VREF[0..4] or ( SDIO_DREFH[0 1], SDIO_DREFM[2 3], SDIO_DREFL[4 5] ) +ADC1_TP_LOW, EFUSE_BLK3, 96, 7, TP_REG EFUSE_RD_ADC1_TP_LOW +ADC2_TP_LOW, EFUSE_BLK3, 112, 7, TP_REG EFUSE_RD_ADC2_TP_LOW +ADC1_TP_HIGH, EFUSE_BLK3, 103, 9, TP_REG EFUSE_RD_ADC1_TP_HIGH +ADC2_TP_HIGH, EFUSE_BLK3, 119, 9, TP_REG EFUSE_RD_ADC2_TP_HIGH diff --git a/components/efuse/esp32/include/esp_efuse_table.h b/components/efuse/esp32/include/esp_efuse_table.h new file mode 100644 index 000000000..c7e7c4448 --- /dev/null +++ b/components/efuse/esp32/include/esp_efuse_table.h @@ -0,0 +1,66 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 + +#ifdef __cplusplus +extern "C" { +#endif + + +// md5_digest 963d6d14dc4bd997fd5d4b9de351745d +// This file was generated automatically from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_FACTORY_CRC[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_CRC[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM[]; +extern const esp_efuse_desc_t* ESP_EFUSE_MAC_CUSTOM_VER[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SECURE_BOOT_KEY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ABS_DONE_0[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_FLASH_KEY[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ENCRYPT_CONFIG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_ENCRYPT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_DECRYPT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_DL_CACHE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_DISABLE_JTAG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CONSOLE_DEBUG_DISABLE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_FLASH_CRYPT_CNT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_FLASH_CRYPT_CNT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK2[]; +extern const esp_efuse_desc_t* ESP_EFUSE_WR_DIS_BLK3[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK2[]; +extern const esp_efuse_desc_t* ESP_EFUSE_RD_DIS_BLK3[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_APP_CPU[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_DIS_BT[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[]; +extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[]; +extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC_VREF_AND_SDIO_DREF[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_LOW[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC1_TP_HIGH[]; +extern const esp_efuse_desc_t* ESP_EFUSE_ADC2_TP_HIGH[]; + +#ifdef __cplusplus +} +#endif + diff --git a/components/efuse/esp32/sources.cmake b/components/efuse/esp32/sources.cmake new file mode 100644 index 000000000..492216be2 --- /dev/null +++ b/components/efuse/esp32/sources.cmake @@ -0,0 +1 @@ +set(EFUSE_SOC_SRCS "esp_efuse_table.c") \ No newline at end of file diff --git a/components/efuse/include/esp_efuse.h b/components/efuse/include/esp_efuse.h new file mode 100644 index 000000000..3ea1680ed --- /dev/null +++ b/components/efuse/include/esp_efuse.h @@ -0,0 +1,294 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _ESP_EFUSE_MANAGER_H_ +#define _ESP_EFUSE_MANAGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_err.h" +#include "esp_log.h" + +#define ESP_ERR_EFUSE 0x1600 /*!< Base error code for efuse api. */ +#define ESP_OK_EFUSE_CNT (ESP_ERR_EFUSE + 0x01) /*!< OK the required number of bits is set. */ +#define ESP_ERR_EFUSE_CNT_IS_FULL (ESP_ERR_EFUSE + 0x02) /*!< Error field is full. */ +#define ESP_ERR_EFUSE_REPEATED_PROG (ESP_ERR_EFUSE + 0x03) /*!< Error repeated programming of programmed bits is strictly forbidden. */ +#define ESP_ERR_CODING (ESP_ERR_EFUSE + 0x04) /*!< Error while a encoding operation. */ + +/** + * @brief Type of eFuse blocks + */ +typedef enum { + EFUSE_BLK0 = 0, /**< Number of eFuse block. Reserved. */ + EFUSE_BLK1 = 1, /**< Number of eFuse block. Used for Flash Encryption. If not using that Flash Encryption feature, they can be used for another purpose. */ + EFUSE_BLK2 = 2, /**< Number of eFuse block. Used for Secure Boot. If not using that Secure Boot feature, they can be used for another purpose. */ + EFUSE_BLK3 = 3 /**< Number of eFuse block. Uses for the purpose of the user. */ +} esp_efuse_block_t; + +/** + * @brief Type of coding scheme + */ +typedef enum { + EFUSE_CODING_SCHEME_NONE = 0, /**< None */ + EFUSE_CODING_SCHEME_3_4 = 1, /**< 3/4 coding */ + EFUSE_CODING_SCHEME_REPEAT = 2, /**< Repeat coding */ +} esp_efuse_coding_scheme_t; + +/** +* @brief Structure eFuse field + */ +typedef struct { + esp_efuse_block_t efuse_block; /**< Block of eFuse */ + uint16_t bit_start; /**< Start bit [0..255] */ + uint16_t bit_count; /**< Length of bit field [1..256]*/ +} esp_efuse_desc_t; + +/** + * @brief Reads bits from EFUSE field and writes it into an array. + * + * The number of read bits will be limited to the minimum value + * from the description of the bits in "field" structure or "dst_size_bits" required size. + * Use "esp_efuse_get_field_size()" function to determine the length of the field. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[out] dst A pointer to array that will contain the result of reading. + * @param[in] dst_size_bits The number of bits required to read. + * If the requested number of bits is greater than the field, + * the number will be limited to the field size. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + */ +esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits); + +/** + * @brief Reads bits from EFUSE field and returns number of bits programmed as "1". + * + * If the bits are set not sequentially, they will still be counted. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[out] out_cnt A pointer that will contain the number of programmed as "1" bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + */ +esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt); + +/** + * @brief Writes array to EFUSE field. + * + * The number of write bits will be limited to the minimum value + * from the description of the bits in "field" structure or "src_size_bits" required size. + * Use "esp_efuse_get_field_size()" function to determine the length of the field. + * After the function is completed, the writing registers are cleared. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in] src A pointer to array that contains the data for writing. + * @param[in] src_size_bits The number of bits required to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits); + +/** + * @brief Writes a required count of bits as "1" to EFUSE field. + * + * If there are no free bits in the field to set the required number of bits to "1", + * ESP_ERR_EFUSE_CNT_IS_FULL error is returned, the field will not be partially recorded. + * After the function is completed, the writing registers are cleared. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in] cnt Required number of programmed as "1" bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_EFUSE_CNT_IS_FULL: Not all requested cnt bits is set. + */ +esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt); + +/** + * @brief Returns the number of bits used by field. + * + * @param[in] field A pointer to the structure describing the fields of efuse. + * + * @return Returns the number of bits used by field. + */ +esp_err_t esp_efuse_get_field_size(const esp_efuse_desc_t* field[]); + +/** + * @brief Returns value of efuse register. + * + * This is a thread-safe implementation. + * Example: EFUSE_BLK2_RDATA3_REG where (blk=2, num_reg=3) + * @param[in] blk Block number of eFuse. + * @param[in] num_reg The register number in the block. + * + * @return Value of register + */ +uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg); + +/** + * @brief Write value to efuse register. + * + * Apply a coding scheme if necessary. + * This is a thread-safe implementation. + * Example: EFUSE_BLK3_WDATA0_REG where (blk=3, num_reg=0) + * @param[in] blk Block number of eFuse. + * @param[in] num_reg The register number in the block. + * @param[in] val Value to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits is strictly forbidden. + */ +esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val); + +/** + * @brief Return efuse coding_scheme for blocks. + * + * @param[in] blk Block number of eFuse. + * @return Return efuse coding_scheme for blocks + */ +esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk); + +/** + * @brief Read key to efuse block starting at the offset and the required size. + * + * @param[in] blk Block number of eFuse. + * @param[in] dst_key A pointer to array that will contain the result of reading. + * @param[in] offset_in_bits Start bit in block. + * @param[in] size_bits The number of bits required to read. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits); + +/** + * @brief Write key to efuse block starting at the offset and the required size. + * + * @param[in] blk Block number of eFuse. + * @param[in] src_key A pointer to array that contains the key for writing. + * @param[in] offset_in_bits Start bit in block. + * @param[in] size_bits The number of bits required to write. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_INVALID_ARG: Error in the passed arguments. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + * - ESP_ERR_EFUSE_REPEATED_PROG: Error repeated programming of programmed bits + */ +esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits); + +/** + * @brief Returns chip version from efuse + * + * @return chip version + */ +uint8_t esp_efuse_get_chip_ver(void); + +/** + * @brief Returns chip package from efuse + * + * @return chip package + */ +uint32_t esp_efuse_get_pkg_ver(void); + +/* @brief Permanently update values written to the efuse write registers + * + * After updating EFUSE_BLKx_WDATAx_REG registers with new values to + * write, call this function to permanently write them to efuse. + * + * @note Setting bits in efuse is permanent, they cannot be unset. + * + * @note Due to this restriction you don't need to copy values to + * Efuse write registers from the matching read registers, bits which + * are set in the read register but unset in the matching write + * register will be unchanged when new values are burned. + * + * @note This function is not threadsafe, if calling code updates + * efuse values from multiple tasks then this is caller's + * responsibility to serialise. + * + * After burning new efuses, the read registers are updated to match + * the new efuse values. + */ +void esp_efuse_burn_new_values(void); + +/* @brief Reset efuse write registers + * + * Efuse write registers are written to zero, to negate + * any changes that have been staged here. + * + * @note This function is not threadsafe, if calling code updates + * efuse values from multiple tasks then this is caller's + * responsibility to serialise. + */ +void esp_efuse_reset(void); + +/* @brief Disable BASIC ROM Console via efuse + * + * By default, if booting from flash fails the ESP32 will boot a + * BASIC console in ROM. + * + * Call this function (from bootloader or app) to permanently + * disable the console on this chip. + */ +void esp_efuse_disable_basic_rom_console(void); + +/* @brief Encode one or more sets of 6 byte sequences into + * 8 bytes suitable for 3/4 Coding Scheme. + * + * This function is only useful if the CODING_SCHEME efuse + * is set to value 1 for 3/4 Coding Scheme. + * + * @param[in] in_bytes Pointer to a sequence of bytes to encode for 3/4 Coding Scheme. Must have length in_bytes_len. After being written to hardware, these bytes will read back as little-endian words. + * @param[out] out_words Pointer to array of words suitable for writing to efuse write registers. Array must contain 2 words (8 bytes) for every 6 bytes in in_bytes_len. Can be a pointer to efuse write registers. + * @param in_bytes_len. Length of array pointed to by in_bytes, in bytes. Must be a multiple of 6. + * + * @return ESP_ERR_INVALID_ARG if either pointer is null or in_bytes_len is not a multiple of 6. ESP_OK otherwise. + */ +esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len); + +/* @brief Write random data to efuse key block write registers + * + * @note Caller is responsible for ensuring efuse + * block is empty and not write protected, before calling. + * + * @note Behaviour depends on coding scheme: a 256-bit key is + * generated and written for Coding Scheme "None", a 192-bit key + * is generated, extended to 256-bits by the Coding Scheme, + * and then writtten for 3/4 Coding Scheme. + * + * @note This function does not burn the new values, caller should + * call esp_efuse_burn_new_values() when ready to do this. + * + * @param blk_wdata0_reg Address of the first data write register + * in the block + */ +void esp_efuse_write_random_key(uint32_t blk_wdata0_reg); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_EFUSE_MANAGER_H_ diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c new file mode 100644 index 000000000..709985786 --- /dev/null +++ b/components/efuse/src/esp_efuse_api.c @@ -0,0 +1,214 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_efuse.h" +#include "esp_efuse_utility.h" +#include "soc/efuse_reg.h" +#include "assert.h" +#include "sdkconfig.h" + +const static char *TAG = "efuse"; + +#if defined(BOOTLOADER_BUILD) +#define EFUSE_LOCK_ACQUIRE() +#define EFUSE_LOCK_RELEASE() +#else +#include +static _lock_t s_efuse_lock; +#define EFUSE_LOCK_ACQUIRE() _lock_acquire(&s_efuse_lock) +#define EFUSE_LOCK_RELEASE() _lock_release(&s_efuse_lock) +#endif + +// Public API functions + +// read value from EFUSE, writing it into an array +esp_err_t esp_efuse_read_field_blob(const esp_efuse_desc_t* field[], void* dst, size_t dst_size_bits) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || dst == NULL || dst_size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + memset((uint8_t *)dst, 0, esp_efuse_utility_get_number_of_items(dst_size_bits, 8)); + err = esp_efuse_utility_process(field, dst, dst_size_bits, esp_efuse_utility_fill_buff); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// read number of bits programmed as "1" in the particular field +esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_cnt) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || out_cnt == NULL) { + err = ESP_ERR_INVALID_ARG; + } else { + *out_cnt = 0; + err = esp_efuse_utility_process(field, out_cnt, 0, esp_efuse_utility_count_once); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// write array to EFUSE +esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || src == NULL || src_size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + esp_efuse_utility_reset(); + err = esp_efuse_utility_process(field, (void*)src, src_size_bits, esp_efuse_utility_write_blob); + + if (err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// program cnt bits to "1" +esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) +{ + EFUSE_LOCK_ACQUIRE(); + esp_err_t err = ESP_OK; + if (field == NULL || cnt == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + esp_efuse_utility_reset(); + err = esp_efuse_utility_process(field, &cnt, 0, esp_efuse_utility_write_cnt); + + if (cnt != 0) { + ESP_LOGE(TAG, "The required number of bits can not be set. [Not set %d]", cnt); + err = ESP_ERR_EFUSE_CNT_IS_FULL; + } + + if (err == ESP_OK_EFUSE_CNT || err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + } + EFUSE_LOCK_RELEASE(); + return err; +} + +// get the length of the field in bits +int esp_efuse_get_field_size(const esp_efuse_desc_t* field[]) +{ + assert(field != NULL); + int bits_counter = 0; + int i = 0; + while (field[i] != NULL) { + bits_counter += field[i]->bit_count; + ++i; + } + return bits_counter; +} + +// reading efuse register. +uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg) +{ + EFUSE_LOCK_ACQUIRE(); + uint32_t ret_val = esp_efuse_utility_read_reg(blk, num_reg); + EFUSE_LOCK_RELEASE(); + return ret_val; +} + +// writing efuse register. +esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val) +{ + EFUSE_LOCK_ACQUIRE(); + esp_efuse_utility_reset(); + esp_err_t err = esp_efuse_utility_write_reg(blk, num_reg, val); + if (err == ESP_OK) { + err = esp_efuse_utility_apply_new_coding_scheme(); + if (err == ESP_OK) { + esp_efuse_utility_burn_efuses(); + } + } + esp_efuse_utility_reset(); + EFUSE_LOCK_RELEASE(); + return err; +} + +// get efuse coding_scheme. +esp_efuse_coding_scheme_t esp_efuse_get_coding_scheme(esp_efuse_block_t blk) +{ + esp_efuse_coding_scheme_t scheme; + if (blk == EFUSE_BLK0) { + scheme = EFUSE_CODING_SCHEME_NONE; + } else { + uint32_t coding_scheme = REG_GET_FIELD(EFUSE_BLK0_RDATA6_REG, EFUSE_CODING_SCHEME); + if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE || + coding_scheme == (EFUSE_CODING_SCHEME_VAL_34 | EFUSE_CODING_SCHEME_VAL_REPEAT)) { + scheme = EFUSE_CODING_SCHEME_NONE; + } else if (coding_scheme == EFUSE_CODING_SCHEME_VAL_34) { + scheme = EFUSE_CODING_SCHEME_3_4; + } else { + scheme = EFUSE_CODING_SCHEME_REPEAT; + } + } + ESP_LOGD(TAG, "coding scheme %d", scheme); + return scheme; +} + +// This function reads the key from the efuse block, starting at the offset and the required size. +esp_err_t esp_efuse_read_block(esp_efuse_block_t blk, void* dst_key, size_t offset_in_bits, size_t size_bits) +{ + esp_err_t err = ESP_OK; + if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || dst_key == NULL || size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + const esp_efuse_desc_t field_desc[] = { + {blk, offset_in_bits, size_bits}, + }; + + const esp_efuse_desc_t* field[] = { + &field_desc[0], + NULL + }; + err = esp_efuse_read_field_blob(field, dst_key, size_bits); + } + return err; +} + +// This function writes the key from the efuse block, starting at the offset and the required size. +esp_err_t esp_efuse_write_block(esp_efuse_block_t blk, const void* src_key, size_t offset_in_bits, size_t size_bits) +{ + esp_err_t err = ESP_OK; + if (blk == EFUSE_BLK0 || blk > EFUSE_BLK3 || src_key == NULL || size_bits == 0) { + err = ESP_ERR_INVALID_ARG; + } else { + const esp_efuse_desc_t field_desc[] = { + {blk, offset_in_bits, size_bits}, + }; + + const esp_efuse_desc_t* field[] = { + &field_desc[0], + NULL + }; + err = esp_efuse_write_field_blob(field, src_key, size_bits); + } + return err; +} diff --git a/components/efuse/src/esp_efuse_fields.c b/components/efuse/src/esp_efuse_fields.c new file mode 100644 index 000000000..2741d0f39 --- /dev/null +++ b/components/efuse/src/esp_efuse_fields.c @@ -0,0 +1,117 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_efuse.h" +#include "esp_efuse_utility.h" +#include "esp_efuse_table.h" +#include "stdlib.h" +#include "esp_types.h" +#include "rom/efuse.h" +#include "assert.h" +#include "esp_err.h" +#include "esp_log.h" +#include "soc/efuse_reg.h" +#include "bootloader_random.h" + +const static char *TAG = "efuse"; + +// Contains functions that provide access to efuse fields which are often used in IDF. + +// Returns chip version from efuse +uint8_t esp_efuse_get_chip_ver(void) +{ + uint8_t chip_ver; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1); + return chip_ver; +} + +// Returns chip package from efuse +uint32_t esp_efuse_get_pkg_ver(void) +{ + uint32_t pkg_ver; + esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_PKG, &pkg_ver, 3); + return pkg_ver; +} + +// Permanently update values written to the efuse write registers +void esp_efuse_burn_new_values(void) +{ + esp_efuse_utility_burn_efuses(); +} + +// Reset efuse write registers +void esp_efuse_reset(void) +{ + esp_efuse_utility_reset(); +} + +// Disable BASIC ROM Console via efuse +void esp_efuse_disable_basic_rom_console(void) +{ + if (esp_efuse_write_field_cnt(ESP_EFUSE_CONSOLE_DEBUG_DISABLE, 1) == ESP_OK) { + ESP_EARLY_LOGI(TAG, "Disable BASIC ROM Console fallback via efuse..."); + } +} + +esp_err_t esp_efuse_apply_34_encoding(const uint8_t *in_bytes, uint32_t *out_words, size_t in_bytes_len) +{ + if (in_bytes == NULL || out_words == NULL || in_bytes_len % 6 != 0) { + return ESP_ERR_INVALID_ARG; + } + + while (in_bytes_len > 0) { + uint8_t out[8]; + uint8_t xor = 0; + uint8_t mul = 0; + for (int i = 0; i < 6; i++) { + xor ^= in_bytes[i]; + mul += (i + 1) * __builtin_popcount(in_bytes[i]); + } + + memcpy(out, in_bytes, 6); // Data bytes + out[6] = xor; + out[7] = mul; + + memcpy(out_words, out, 8); + + in_bytes_len -= 6; + in_bytes += 6; + out_words += 2; + } + + return ESP_OK; +} + +void esp_efuse_write_random_key(uint32_t blk_wdata0_reg) +{ + uint32_t buf[8]; + uint8_t raw[24]; + uint32_t coding_scheme = REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_CODING_SCHEME_M; + + if (coding_scheme == EFUSE_CODING_SCHEME_VAL_NONE) { + bootloader_fill_random(buf, sizeof(buf)); + } else { // 3/4 Coding Scheme + bootloader_fill_random(raw, sizeof(raw)); + esp_err_t r = esp_efuse_apply_34_encoding(raw, buf, sizeof(raw)); + assert(r == ESP_OK); + } + + ESP_LOGV(TAG, "Writing random values to address 0x%08x", blk_wdata0_reg); + for (int i = 0; i < 8; i++) { + ESP_LOGV(TAG, "EFUSE_BLKx_WDATA%d_REG = 0x%08x", i, buf[i]); + REG_WRITE(blk_wdata0_reg + 4*i, buf[i]); + } + bzero(buf, sizeof(buf)); + bzero(raw, sizeof(raw)); +} diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c new file mode 100644 index 000000000..fa360e46b --- /dev/null +++ b/components/efuse/src/esp_efuse_utility.c @@ -0,0 +1,512 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_efuse_utility.h" + +#include "soc/efuse_reg.h" +#include "esp_log.h" +#include "assert.h" +#include "sdkconfig.h" +#include + +static const char *TAG = "efuse"; + +#define COUNT_EFUSE_BLOCKS 4 /* The number of blocks. */ +#define COUNT_EFUSE_REG_PER_BLOCK 8 /* The number of registers per block. */ +#define EFUSE_CONF_WRITE 0x5A5A /* eFuse_pgm_op_ena, force no rd/wr disable. */ +#define EFUSE_CONF_READ 0x5AA5 /* eFuse_read_op_ena, release force. */ +#define EFUSE_CMD_PGM 0x02 /* Command to program. */ +#define EFUSE_CMD_READ 0x01 /* Command to read. */ + +// Array for emulate efuse registers. +#ifdef CONFIG_EFUSE_VIRTUAL +static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK]; +#endif + +/** + * @brief Structure range address by blocks + */ +typedef struct { + uint32_t start; + uint32_t end; +} esp_efuse_range_addr_t; + +/*Range addresses to read blocks*/ +static const esp_efuse_range_addr_t range_read_addr_blocks[] = { + {EFUSE_BLK0_RDATA0_REG, EFUSE_BLK0_RDATA6_REG}, // range address of EFUSE_BLK0 + {EFUSE_BLK1_RDATA0_REG, EFUSE_BLK1_RDATA7_REG}, // range address of EFUSE_BLK1 + {EFUSE_BLK2_RDATA0_REG, EFUSE_BLK2_RDATA7_REG}, // range address of EFUSE_BLK2 + {EFUSE_BLK3_RDATA0_REG, EFUSE_BLK3_RDATA7_REG} // range address of EFUSE_BLK3 +}; + +/*Range addresses to write blocks*/ +static const esp_efuse_range_addr_t range_write_addr_blocks[] = { + {EFUSE_BLK0_WDATA0_REG, EFUSE_BLK0_WDATA6_REG}, // range address of EFUSE_BLK0 + {EFUSE_BLK1_WDATA0_REG, EFUSE_BLK1_WDATA7_REG}, // range address of EFUSE_BLK1 + {EFUSE_BLK2_WDATA0_REG, EFUSE_BLK2_WDATA7_REG}, // range address of EFUSE_BLK2 + {EFUSE_BLK3_WDATA0_REG, EFUSE_BLK3_WDATA7_REG} // range address of EFUSE_BLK3 +}; + +static int get_reg_num(int bit_start, int bit_count, int i_reg); +static int get_starting_bit_num_in_reg(int bit_start, int i_reg); +static uint32_t get_mask(unsigned int bit_count, unsigned int shift); +static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg); +static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value); +static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob); +static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt); +static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits); + +// This function processes the field by calling the passed function. +esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc) +{ + esp_err_t err = ESP_OK; + int bits_counter = 0; + + // get and check size. + int field_len = esp_efuse_get_field_size(field); + int req_size = (ptr_size_bits == 0) ? field_len : MIN(ptr_size_bits, field_len); + + int i = 0; + while (err == ESP_OK && req_size > bits_counter && field[i] != NULL) { + if (check_range_of_bits(field[i]->efuse_block, field[i]->bit_start, field[i]->bit_count) == false) { + ESP_LOGE(TAG, "Range of data does not match the coding scheme"); + err = ESP_ERR_CODING; + } + int i_reg = 0; + int num_reg; + while (err == ESP_OK && req_size > bits_counter && + (num_reg = get_reg_num(field[i]->bit_start, field[i]->bit_count, i_reg)) != -1) { + + int start_bit = get_starting_bit_num_in_reg(field[i]->bit_start, i_reg); + int num_bits = get_count_bits_in_reg(field[i]->bit_start, field[i]->bit_count, i_reg); + if ((bits_counter + num_bits) > req_size) { // Limits the length of the field. + num_bits = req_size - bits_counter; + } + ESP_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit", + (int)field[i]->efuse_block, num_reg, num_bits, start_bit); + err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter); + ++i_reg; + } + i++; + } + assert(bits_counter <= req_size); + return err; +} + + +// Read efuse register and write this value to array. +esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter) +{ + uint8_t* blob = (uint8_t *) arr_out; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + uint64_t reg_of_aligned_bits = (reg >> bit_start) & get_mask(bit_count, 0); + + int shift_bit = (*bits_counter) % 8; + if (shift_bit != 0) { + blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits << shift_bit); + shift_bit = ((8 - shift_bit) < bit_count) ? (8 - shift_bit) : bit_count; + (*bits_counter) += shift_bit; + bit_count -= shift_bit; + } + + int sum_shift = 0; + while (bit_count > 0) { + sum_shift += shift_bit; + blob[(*bits_counter) / 8] |= (uint8_t)(reg_of_aligned_bits >> sum_shift); + shift_bit = (bit_count > 8) ? 8 : bit_count; + (*bits_counter) += shift_bit; + bit_count -= shift_bit; + }; + return ESP_OK; +} + +// Count a set bits. +esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter) +{ + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + *((size_t *)out_cnt) += __builtin_popcount(reg & get_mask(bit_count, bit_start)); // Returns the number of 1-bits in reg. + *bits_counter += bit_count; + return ESP_OK; +} + +// Fill registers from array for writing. +esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter) +{ + uint32_t reg_to_write = fill_reg(bit_start, bit_count, (uint8_t *)arr_in, bits_counter); + return esp_efuse_utility_write_reg(efuse_block, num_reg, reg_to_write); +} + +// fill registers with the required number of bits for writing. +esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter) +{ + esp_err_t err = ESP_OK; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + size_t* set_bits = (size_t*)cnt; + uint32_t mask = get_mask(bit_count, bit_start); + uint32_t reg_masked_bits = reg & mask; + if ((reg_masked_bits ^ mask) != 0) {// register has free bits to set them to 1? + uint32_t reg_to_write = set_cnt_in_reg(bit_start, bit_count, reg_masked_bits, set_bits); + write_reg(efuse_block, num_reg, reg_to_write); + } + *bits_counter += bit_count; + if ((*set_bits) == 0) { + err = ESP_OK_EFUSE_CNT; + } + return err; +} + +// Reset efuse write registers +void esp_efuse_utility_reset(void) +{ + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { + REG_WRITE(addr_wr_block, 0); + } + } +} + +// Burn values written to the efuse write registers +void esp_efuse_utility_burn_efuses(void) +{ +#ifdef CONFIG_EFUSE_VIRTUAL + ESP_LOGE(TAG, "Not really burning any efuses!"); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); + if (scheme == EFUSE_CODING_SCHEME_3_4) { + uint8_t buf[COUNT_EFUSE_REG_PER_BLOCK * 4] = { 0 }; + int i = 0; + for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) { + *((uint32_t*)buf + i) = REG_READ(addr_wr_block); + } + int j = 0; + uint32_t out_buf[COUNT_EFUSE_REG_PER_BLOCK] = { 0 }; + for (int k = 0; k < 4; ++k, ++j) { + memcpy((uint8_t*)out_buf + j * 6, &buf[k * 8], 6); + } + for (int k = 0; k < COUNT_EFUSE_REG_PER_BLOCK; ++k) { + REG_WRITE(range_write_addr_blocks[num_block].start + k * 4, out_buf[k]); + } + } + int subblock = 0; + for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4) { + virt_blocks[num_block][subblock++] |= REG_READ(addr_wr_block); + } + } +#else + // Permanently update values written to the efuse write registers + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE); + REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM); + while (REG_READ(EFUSE_CMD_REG) != 0) {}; + REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_READ); + REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_READ); + while (REG_READ(EFUSE_CMD_REG) != 0) {}; +#endif + esp_efuse_utility_reset(); +} + + +// Erase the virt_blocks array. +void esp_efuse_utility_erase_virt_blocks() +{ +#ifdef CONFIG_EFUSE_VIRTUAL + memset(virt_blocks, 0, sizeof(virt_blocks)); +#endif +} + +// Fills the virt_blocks array by values from efuse_Rdata. +void esp_efuse_utility_update_virt_blocks() +{ +#ifdef CONFIG_EFUSE_VIRTUAL + ESP_LOGI(TAG, "Emulate efuse is enabled"); + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + int subblock = 0; + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) { + virt_blocks[num_block][subblock++] = REG_READ(addr_rd_block); + } + ESP_LOGD(TAG, "virt_blocks[%d] is filled by EFUSE_BLOCK%d", num_block, num_block); + } +#else + ESP_LOGI(TAG, "Emulate efuse is disabled"); +#endif +} + +// Prints efuse values for all registers. +void esp_efuse_utility_debug_dump_blocks() +{ + printf("EFUSE_BLKx:\n"); +#ifdef CONFIG_EFUSE_VIRTUAL + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + int num_reg = 0; + printf("%d) ", num_block); + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, num_reg++) { + printf("0x%08x ", virt_blocks[num_block][num_reg]); + } + printf("\n"); + } +#else + for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + printf("%d) ", num_block); + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) { + printf("0x%08x ", REG_READ(addr_rd_block)); + } + printf("\n"); + } +#endif + printf("\n"); +} + +// returns the number of array elements for placing these bits in an array with the length of each element equal to size_of_base. +int esp_efuse_utility_get_number_of_items(int bits, int size_of_base) +{ + return bits / size_of_base + (bits % size_of_base > 0 ? 1 : 0); +} + +// Writing efuse register with checking of repeated programming of programmed bits. +esp_err_t esp_efuse_utility_write_reg(esp_efuse_block_t efuse_block, unsigned int num_reg, uint32_t reg_to_write) +{ + esp_err_t err = ESP_OK; + uint32_t reg = esp_efuse_utility_read_reg(efuse_block, num_reg); + if (reg & reg_to_write) { + ESP_LOGE(TAG, "Repeated programming of programmed bits is strictly forbidden 0x%08x", reg & reg_to_write); + err = ESP_ERR_EFUSE_REPEATED_PROG; + } else { + write_reg(efuse_block, num_reg, reg_to_write); + } + return err; +} + +// Reading efuse register. +uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg) +{ + assert(blk >= 0 && blk <= 3); + if (blk == 0) { + assert(num_reg <= 6); + } else { + assert(num_reg <= 7); + } + + uint32_t value; +#ifdef CONFIG_EFUSE_VIRTUAL + value = virt_blocks[blk][num_reg]; +#else + value = REG_READ(range_read_addr_blocks[blk].start + num_reg * 4); +#endif + return value; +} + +// Private functions + +// writing efuse register. +static void write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t value) +{ + assert(blk >= 0 && blk <= 3); + if (blk == 0) { + assert(num_reg <= 6); + } else { + assert(num_reg <= 7); + } + uint32_t addr_wr_reg = range_write_addr_blocks[blk].start + num_reg * 4; + uint32_t reg_to_write = REG_READ(addr_wr_reg) | value; + // The register can be written in parts so we combine the new value with the one already available. + REG_WRITE(addr_wr_reg, reg_to_write); +} + +// return mask with required the number of ones with shift. +static uint32_t get_mask(unsigned int bit_count, unsigned int shift) +{ + uint32_t mask; + if (bit_count != 32) { + mask = (1 << bit_count) - 1; + } else { + mask = 0xFFFFFFFF; + } + return mask << shift; +} + +// return the register number in the array. return -1 if all registers for field was selected. +static int get_reg_num(int bit_start, int bit_count, int i_reg) +{ + int num_reg = i_reg + bit_start / 32; + + if (num_reg > (bit_start + bit_count - 1) / 32) { + return -1; + } + + return num_reg; +} + +// returns the starting bit number in the register. +static int get_starting_bit_num_in_reg(int bit_start, int i_reg) +{ + return (i_reg == 0) ? bit_start % 32 : 0; +} + +// Returns the number of bits in the register. +static int get_count_bits_in_reg(int bit_start, int bit_count, int i_reg) +{ + int ret_count = 0; + int num_reg = 0; + int last_used_bit = (bit_start + bit_count - 1); + for (int num_bit = bit_start; num_bit <= last_used_bit; ++num_bit) { + ++ret_count; + if ((((num_bit + 1) % 32) == 0) || (num_bit == last_used_bit)) { + if (i_reg == num_reg++) { + return ret_count; + } + ret_count = 0; + } + } + return 0; +} + +// fill efuse register from array. +static uint32_t fill_reg(int bit_start_in_reg, int bit_count_in_reg, uint8_t* blob, int* filled_bits_blob) +{ + uint32_t reg_to_write = 0; + uint32_t temp_blob_32; + int shift_bit = (*filled_bits_blob) % 8; + if (shift_bit != 0) { + temp_blob_32 = blob[(*filled_bits_blob) / 8] >> shift_bit; + shift_bit = ((8 - shift_bit) < bit_count_in_reg) ? (8 - shift_bit) : bit_count_in_reg; + reg_to_write = temp_blob_32 & get_mask(shift_bit, 0); + (*filled_bits_blob) += shift_bit; + bit_count_in_reg -= shift_bit; + } + + int shift_reg = shift_bit; + while (bit_count_in_reg > 0) { + temp_blob_32 = blob[(*filled_bits_blob) / 8]; + shift_bit = (bit_count_in_reg > 8) ? 8 : bit_count_in_reg; + reg_to_write |= (temp_blob_32 & get_mask(shift_bit, 0)) << shift_reg; + (*filled_bits_blob) += shift_bit; + bit_count_in_reg -= shift_bit; + shift_reg += 8; + }; + return reg_to_write << bit_start_in_reg; +} + +// sets a required count of bits as "1". +static uint32_t set_cnt_in_reg(int bit_start_in_reg, int bit_count_used_in_reg, uint32_t reg_masked, size_t* cnt) +{ + assert((bit_start_in_reg + bit_count_used_in_reg) <= 32); + uint32_t reg_to_write = 0; + for (int i = bit_start_in_reg; i < bit_start_in_reg + bit_count_used_in_reg; ++i) { + if ((reg_masked & (1 << i)) == 0) { + reg_to_write |= (1 << i); + if (--(*cnt) == 0) { + break; + } + } + } + return reg_to_write; +} + +// check range of bits for any coding scheme. +static bool check_range_of_bits(esp_efuse_block_t blk, int offset_in_bits, int size_bits) +{ + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(blk); + int max_num_bit = offset_in_bits + size_bits; + if ((scheme == EFUSE_CODING_SCHEME_NONE && max_num_bit > 256) || + (scheme == EFUSE_CODING_SCHEME_3_4 && max_num_bit > 192) || + (scheme == EFUSE_CODING_SCHEME_REPEAT && max_num_bit > 128)) { + return false; + } + return true; +} + +static bool read_w_data_and_check_fill(esp_efuse_block_t num_block, uint32_t *buf_w_data) +{ + bool blk_is_filled = false; + int i = 0; + for (uint32_t addr_wr_block = range_write_addr_blocks[num_block].start; addr_wr_block <= range_write_addr_blocks[num_block].end; addr_wr_block += 4, ++i) { + buf_w_data[i] = REG_READ(addr_wr_block); + if (buf_w_data[i] != 0) { + REG_WRITE(addr_wr_block, 0); + blk_is_filled = true; + } + } + return blk_is_filled; +} + +static void read_r_data(esp_efuse_block_t num_block, uint32_t* buf_r_data) +{ + int i = 0; + for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4, ++i) { + buf_r_data[i] = REG_READ(addr_rd_block); + } +} + +// After esp_efuse_write.. functions EFUSE_BLKx_WDATAx_REG were filled is not coded values. +// This function reads EFUSE_BLKx_WDATAx_REG registers, applies coding scheme and writes encoded values back to EFUSE_BLKx_WDATAx_REG. +esp_err_t esp_efuse_utility_apply_new_coding_scheme() +{ + uint8_t buf_w_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; + uint8_t buf_r_data[COUNT_EFUSE_REG_PER_BLOCK * 4]; + uint32_t reg[COUNT_EFUSE_REG_PER_BLOCK]; + // start with EFUSE_BLK1. EFUSE_BLK0 - always uses EFUSE_CODING_SCHEME_NONE. + for (int num_block = 1; num_block < COUNT_EFUSE_BLOCKS; num_block++) { + esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block); + // check and apply a new coding scheme. + if (scheme != EFUSE_CODING_SCHEME_NONE) { + memset(buf_w_data, 0, sizeof(buf_w_data)); + memset((uint8_t*)reg, 0, sizeof(reg)); + if (read_w_data_and_check_fill(num_block, (uint32_t*)buf_w_data) == true) { + read_r_data(num_block, (uint32_t*)buf_r_data); + if (scheme == EFUSE_CODING_SCHEME_3_4) { + if (*((uint32_t*)buf_w_data + 6) != 0 || *((uint32_t*)buf_w_data + 7) != 0) { + return ESP_ERR_CODING; + } + for (int i = 0; i < 24; ++i) { + if (buf_w_data[i] != 0) { + int st_offset_buf = (i / 6) * 6; + // check that place is free. + for (int n = st_offset_buf; n < st_offset_buf + 6; ++n) { + if (buf_r_data[n] != 0) { + ESP_LOGE(TAG, "Bits are not empty. Write operation is forbidden."); + return ESP_ERR_CODING; + } + } + + esp_err_t err = esp_efuse_apply_34_encoding(&buf_w_data[st_offset_buf], reg, 6); + if (err != ESP_OK) { + return err; + } + + int num_reg = (st_offset_buf / 6) * 2; + for (int r = 0; r < 2; r++) { + REG_WRITE(range_write_addr_blocks[num_block].start + (num_reg + r) * 4, reg[r]); + } + i = st_offset_buf + 5; + } + } + } else if (scheme == EFUSE_CODING_SCHEME_REPEAT) { + uint32_t* buf_32 = (uint32_t*)buf_w_data; + for (int i = 4; i < 8; ++i) { + if (*(buf_32 + i) != 0) { + return ESP_ERR_CODING; + } + } + for (int i = 0; i < 4; ++i) { + if (buf_32[i] != 0) { + REG_WRITE(range_write_addr_blocks[num_block].start + i * 4, buf_32[i]); + REG_WRITE(range_write_addr_blocks[num_block].start + (i + 4) * 4, buf_32[i]); + } + } + } + } + } + } + return ESP_OK; +} diff --git a/components/efuse/src/esp_efuse_utility.h b/components/efuse/src/esp_efuse_utility.h new file mode 100644 index 000000000..18d8b5886 --- /dev/null +++ b/components/efuse/src/esp_efuse_utility.h @@ -0,0 +1,140 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#ifndef _ESP_EFUSE_UTILITY_H_ +#define _ESP_EFUSE_UTILITY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "esp_types.h" +#include "esp_err.h" +#include "esp_efuse.h" + +/** + * @brief This is type of function that will handle the efuse field register. + * + * @param[in] num_reg The register number in the block. + * @param[in] efuse_block Block number. + * @param[in] bit_start Start bit in the register. + * @param[in] bit_count The number of bits used in the register. + * @param[in/out] arr A pointer to an array or variable. + * @param[in/out] bits_counter Counter bits. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - other efuse component errors. + */ +typedef esp_err_t (*efuse_func_proc_t) (unsigned int num_reg, esp_efuse_block_t efuse_block, int starting_bit_num_in_reg, int num_bits_used_in_reg, void* arr, int* bits_counter); + +/** + * @brief This function processes the field by calling the passed function. + * + * This function selects the field, checks the length, and calls the register processing function. + * @param[in] field A pointer to the structure describing the fields of efuse. + * @param[in/out] ptr A pointer to an array that is used to read / write from / to the efuse field. + * @param[in] ptr_size_bits The size of the data in bits for the efuse field. if = 0 then read all field bits. + * @param[in] func_proc This is the function that will handle the efuse fields. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - other efuse component errors. + */ +esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, size_t ptr_size_bits, efuse_func_proc_t func_proc); + +/** + * @brief Write register with the required number of "1" bits. + * @param[in/out] cnt The number of bits you need to set in the field. + */ +esp_err_t esp_efuse_utility_write_cnt(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* cnt, int* bits_counter); + +/** + * @brief Fill registers from array for writing. + * @param[in] arr_in A pointer to an array in which the data for the writing. + */ +esp_err_t esp_efuse_utility_write_blob(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_in, int* bits_counter); + +/** + * @brief Count a set bits in register. + * @param[in/out] out_cnt A pointer to size_t variable which will contain the number of "1" bits. + */ +esp_err_t esp_efuse_utility_count_once(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* out_cnt, int* bits_counter); + +/** + * @brief Read efuse register and write this value to array. + * @param[out] arr_out A pointer to array that will contain the result of reading. + */ +esp_err_t esp_efuse_utility_fill_buff(unsigned int num_reg, esp_efuse_block_t efuse_block, int bit_start, int bit_count, void* arr_out, int* bits_counter); + +/** + * @brief Burn values written to the efuse write registers. + * + * If CONFIG_EFUSE_VIRTUAL is set, writing will not be performed. + * After the function is completed, the writing registers are cleared. + */ +void esp_efuse_utility_burn_efuses(void); + +/** + * @brief Returns the number of array elements for placing these "bits" in an array with the length of each element equal to "size_of_base". + */ +int esp_efuse_utility_get_number_of_items(int bits, int size_of_base); + +/** + * @brief Reading efuse register. + */ +uint32_t esp_efuse_utility_read_reg(esp_efuse_block_t blk, unsigned int num_reg); + +/** + * @brief Writing efuse register with checking of repeated programming of programmed bits. + */ +esp_err_t esp_efuse_utility_write_reg(unsigned int num_reg, esp_efuse_block_t efuse_block, uint32_t reg_to_write); + +/* @brief Reset efuse write registers + * + * Efuse write registers are written to zero, to negate + * any changes that have been staged here. + */ +void esp_efuse_utility_reset(void); + +/** + * @brief Fills the virt_blocks array by values from efuse_Rdata. + */ +void esp_efuse_utility_update_virt_blocks(); + +/** + * @brief Prints efuse values for all registers. + */ +void esp_efuse_utility_debug_dump_blocks(); + +/** + * @brief Erase the virt_blocks array. + */ +void esp_efuse_utility_erase_virt_blocks(); + +/** + * @brief Apply coding_scheme to write registers. + * + * @return + * - ESP_OK: The operation was successfully completed. + * - ESP_ERR_CODING: Error range of data does not match the coding scheme. + */ +esp_err_t esp_efuse_utility_apply_new_coding_scheme(); + +#ifdef __cplusplus +} +#endif + +#endif // _ESP_EFUSE_UTILITY_H_ diff --git a/components/efuse/test/CMakeLists.txt b/components/efuse/test/CMakeLists.txt new file mode 100644 index 000000000..28d0b2e7a --- /dev/null +++ b/components/efuse/test/CMakeLists.txt @@ -0,0 +1,6 @@ +set(COMPONENT_SRCDIRS ".") +set(COMPONENT_ADD_INCLUDEDIRS "." "include") + +set(COMPONENT_REQUIRES unity test_utils efuse bootloader_support) + +register_component() \ No newline at end of file diff --git a/components/efuse/test/component.mk b/components/efuse/test/component.mk new file mode 100644 index 000000000..5dda86047 --- /dev/null +++ b/components/efuse/test/component.mk @@ -0,0 +1,6 @@ +# +#Component Makefile +# +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive diff --git a/components/efuse/test/esp_efuse_test_table.c b/components/efuse/test/esp_efuse_test_table.c new file mode 100644 index 000000000..92977d7c5 --- /dev/null +++ b/components/efuse/test/esp_efuse_test_table.c @@ -0,0 +1,103 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 "esp_efuse.h" +#include "esp_efuse_test_table.h" + +// md5_digest dac4d84347dab29412b8b8713b4b0065 +// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +static const esp_efuse_desc_t TEST1_LEN_8[] = { + {EFUSE_BLK3, 0, 8}, // TEST field, +}; + +static const esp_efuse_desc_t TEST2_LEN_16[] = { + {EFUSE_BLK3, 10, 8}, // TEST field, + {EFUSE_BLK3, 80, 8}, // TEST field, +}; + +static const esp_efuse_desc_t TEST3_LEN_6[] = { + {EFUSE_BLK3, 22, 6}, // TEST field, +}; + +static const esp_efuse_desc_t TEST4_LEN_182[] = { + {EFUSE_BLK1, 22, 49}, // TEST field, + {EFUSE_BLK1, 89, 39}, // TEST field, + {EFUSE_BLK1, 71, 18}, // TEST field, + {EFUSE_BLK1, 0, 16}, // TEST field, + {EFUSE_BLK2, 0, 17}, // TEST field, + {EFUSE_BLK2, 60, 43}, // TEST field, +}; + +static const esp_efuse_desc_t TEST5_LEN_1[] = { + {EFUSE_BLK1, 16, 1}, // TEST field, +}; + +static const esp_efuse_desc_t TEST6_LEN_17[] = { + {EFUSE_BLK1, 17, 1}, // TEST field, + {EFUSE_BLK2, 17, 2}, // TEST field, + {EFUSE_BLK3, 29, 4}, // TEST field, + {EFUSE_BLK2, 31, 3}, // TEST field, + {EFUSE_BLK3, 60, 6}, // TEST field, + {EFUSE_BLK2, 127, 1}, // TEST field, +}; + + + + + +const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[] = { + &TEST1_LEN_8[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[] = { + &TEST2_LEN_16[0], // TEST field + &TEST2_LEN_16[1], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[] = { + &TEST3_LEN_6[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[] = { + &TEST4_LEN_182[0], // TEST field + &TEST4_LEN_182[1], // TEST field + &TEST4_LEN_182[2], // TEST field + &TEST4_LEN_182[3], // TEST field + &TEST4_LEN_182[4], // TEST field + &TEST4_LEN_182[5], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[] = { + &TEST5_LEN_1[0], // TEST field + NULL +}; + +const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[] = { + &TEST6_LEN_17[0], // TEST field + &TEST6_LEN_17[1], // TEST field + &TEST6_LEN_17[2], // TEST field + &TEST6_LEN_17[3], // TEST field + &TEST6_LEN_17[4], // TEST field + &TEST6_LEN_17[5], // TEST field + NULL +}; + diff --git a/components/efuse/test/esp_efuse_test_table.csv b/components/efuse/test/esp_efuse_test_table.csv new file mode 100644 index 000000000..24798c1a3 --- /dev/null +++ b/components/efuse/test/esp_efuse_test_table.csv @@ -0,0 +1,33 @@ +# field_name, | efuse_block, | bit_start, | bit_count, |comment # +# | (EFUSE_BLK0 | (0..255) | (1..256) | # +# | EFUSE_BLK1 | | | # +# | EFUSE_BLK2 | | | # +# | EFUSE_BLK3) | | | # +########################################################################## + +# To generate a new source files. Run two commands: +# cd ~/esp/esp-idf/components/efuse/ +# ./efuse_table_gen.py test/esp_efuse_test_table.csv + +TEST1_LEN_8, EFUSE_BLK3, 0, 8, TEST field + +TEST2_LEN_16, EFUSE_BLK3, 10, 8, TEST field +, EFUSE_BLK3, 80, 8, TEST field + +TEST3_LEN_6, EFUSE_BLK3, 22, 6, TEST field + +TEST4_LEN_182, EFUSE_BLK1, 22, 49, TEST field +, EFUSE_BLK1, 89, 39, TEST field +, EFUSE_BLK1, 71, 18, TEST field +, EFUSE_BLK1, 0, 16, TEST field +, EFUSE_BLK2, 0, 17, TEST field +, EFUSE_BLK2, 60, 43, TEST field + +TEST5_LEN_1, EFUSE_BLK1, 16, 1, TEST field + +TEST6_LEN_17, EFUSE_BLK1, 17, 1, TEST field +, EFUSE_BLK2, 17, 2, TEST field +, EFUSE_BLK3, 29, 4, TEST field +, EFUSE_BLK2, 31, 3, TEST field +, EFUSE_BLK3, 60, 6, TEST field +, EFUSE_BLK2, 127, 1, TEST field diff --git a/components/efuse/test/include/esp_efuse_test_table.h b/components/efuse/test/include/esp_efuse_test_table.h new file mode 100644 index 000000000..b47ffaf18 --- /dev/null +++ b/components/efuse/test/include/esp_efuse_test_table.h @@ -0,0 +1,36 @@ +// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// +// 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 + +#ifdef __cplusplus +extern "C" { +#endif + + +// md5_digest dac4d84347dab29412b8b8713b4b0065 +// This file was generated automatically from the file esp_efuse_test_table.csv. DO NOT CHANGE THIS FILE MANUALLY. +// If you want to change some fields, you need to change esp_efuse_test_table.csv file then build system will generate this header file +// To show efuse_table run the command 'make show_efuse_table'. + + +extern const esp_efuse_desc_t* ESP_EFUSE_TEST1_LEN_8[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST2_LEN_16[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST3_LEN_6[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST4_LEN_182[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST5_LEN_1[]; +extern const esp_efuse_desc_t* ESP_EFUSE_TEST6_LEN_17[]; + +#ifdef __cplusplus +} +#endif + diff --git a/components/efuse/test/test_efuse.c b/components/efuse/test/test_efuse.c new file mode 100644 index 000000000..c41e2b5e1 --- /dev/null +++ b/components/efuse/test/test_efuse.c @@ -0,0 +1,546 @@ +#include +#include +#include +#include +#include +#include "unity.h" +#include "esp_log.h" +#include +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "../src/esp_efuse_utility.h" +#include "esp_efuse_test_table.h" +#include "rom/efuse.h" +#include "bootloader_random.h" +#include "sdkconfig.h" + +static const char* TAG = "efuse_test"; + +static void test_read_blob(void) +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + uint8_t mac[6]; + + ESP_LOGI(TAG, "1. Read MAC address"); + memset(mac, 0, sizeof(mac)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, sizeof(mac) * 8)); + TEST_ASSERT_EQUAL_INT(sizeof(mac) * 8, esp_efuse_get_field_size(ESP_EFUSE_MAC_FACTORY)); + ESP_LOGI(TAG, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + ESP_LOGI(TAG, "2. Check CRC by MAC"); + uint8_t crc; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY_CRC, &crc, 8)); + TEST_ASSERT_EQUAL_HEX8(crc, esp_crc8(mac, sizeof(mac))); + + ESP_LOGI(TAG, "3. Test check args"); + uint32_t test_var; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, NULL, 1)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &test_var, 0)); + + uint8_t half_byte; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &half_byte, 4)); + TEST_ASSERT_EQUAL_HEX8(mac[0]&0x0F, half_byte); + + uint8_t buff[7] = {0x59}; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &buff, sizeof(buff) * 8)); + TEST_ASSERT_TRUE_MESSAGE(memcmp(mac, buff, sizeof(mac)) == 0, "Operation read blob is not success"); + TEST_ASSERT_EQUAL_HEX8(0, buff[6]); +} + +TEST_CASE("efuse test read_field_blob", "[efuse]") +{ + test_read_blob(); +} + +static void test_read_cnt(void) +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + size_t cnt; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, NULL)); + + ESP_LOGI(TAG, "2. Read MAC address"); + uint8_t mac[6]; + memset(mac, 0, sizeof(mac)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, &mac, 48)); + + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_MAC_FACTORY, &cnt)); + size_t cnt_summ = 0; + for (int i = 0; i < sizeof(mac); ++i) { + cnt_summ += __builtin_popcount(mac[i]); + } + TEST_ASSERT_EQUAL_INT(cnt_summ, cnt); +} + +TEST_CASE("efuse test read_field_cnt", "[efuse]") +{ + test_read_cnt(); +} + +// If using efuse is real, then turn off writing tests. +#ifdef CONFIG_EFUSE_VIRTUAL +static void test_write_blob(void) +{ + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + uint16_t test1_len_8 = 0x5FAA; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_MAC_FACTORY, &test1_len_8, 0)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, NULL, 8)); + TEST_ASSERT_EQUAL_HEX16(0x5FAA, test1_len_8); + + ESP_LOGI(TAG, "2. Test write operation"); + + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 7)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 9)); + uint16_t val_read1 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 8)); + TEST_ASSERT_EQUAL_HEX16(test1_len_8&((1 << 7) - 1), val_read1); + + uint16_t test1_len_8_hi = test1_len_8 & ~((1 << 7) - 1); + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8_hi, 8)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST1_LEN_8, &test1_len_8, 8)); + val_read1 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST1_LEN_8, &val_read1, 16)); + TEST_ASSERT_EQUAL_HEX16(test1_len_8&0x00FF, val_read1); + + uint16_t test2_len_16 = 0xAA55; + uint32_t val_32 = test2_len_16; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &val_32, 17)); + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16)); + uint16_t test_16 = 0; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test_16, 16)); + TEST_ASSERT_EQUAL_HEX16(test2_len_16, test_16); + + ESP_LOGI(TAG, "3. Test field with one bit"); + uint8_t test5_len_1; + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 0; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_OK(esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_ERR(ESP_ERR_EFUSE_REPEATED_PROG, esp_efuse_write_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + + esp_efuse_utility_debug_dump_blocks(); +} + +TEST_CASE("efuse test write_field_blob", "[efuse]") +{ + test_write_blob(); +} + +static void test_write_cnt(void) +{ + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "1. Test check args"); + size_t test3_len_6 = 5; + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_MAC_FACTORY, 0)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(NULL, 5)); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 0)); + + ESP_LOGI(TAG, "2. Test write operation"); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(0, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(1, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 1)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(2, test3_len_6); + + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST3_LEN_6, 3)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST3_LEN_6, &test3_len_6)); + TEST_ASSERT_EQUAL_INT(5, test3_len_6); + + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "3. Test field is full set"); + int max_bits = esp_efuse_get_field_size(ESP_EFUSE_TEST4_LEN_182); + size_t test4_len_182; + esp_efuse_utility_debug_dump_blocks(); + for (int i = 0; i < max_bits / 26; ++i) { + ESP_LOGD(TAG, "# %d", i); + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 26)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST4_LEN_182, &test4_len_182)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_INT((i + 1) * 26, test4_len_182); + } + + esp_efuse_utility_debug_dump_blocks(); + + ESP_LOGI(TAG, "4. Test field ESP_EFUSE_TEST4_LEN_182 is full"); + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST4_LEN_182, 1)); + + ESP_LOGI(TAG, "3. Test field with one bit"); + size_t test5_len_1; + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(0, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1)); + + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST5_LEN_1, &test5_len_1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST5_LEN_1, &test5_len_1, 1)); + TEST_ASSERT_EQUAL_HEX8(1, test5_len_1); + + test5_len_1 = 1; + TEST_ESP_ERR(ESP_ERR_EFUSE_CNT_IS_FULL, esp_efuse_write_field_cnt(ESP_EFUSE_TEST5_LEN_1, test5_len_1)); + + esp_efuse_utility_debug_dump_blocks(); + ESP_LOGI(TAG, "4. Test field test2_len_16"); + size_t test2_len_16 = 11; + TEST_ESP_OK(esp_efuse_write_field_cnt(ESP_EFUSE_TEST2_LEN_16, test2_len_16)); + TEST_ESP_OK(esp_efuse_read_field_cnt(ESP_EFUSE_TEST2_LEN_16, &test2_len_16)); + TEST_ASSERT_EQUAL_HEX16(11, test2_len_16); + TEST_ESP_OK(esp_efuse_read_field_blob(ESP_EFUSE_TEST2_LEN_16, &test2_len_16, 16)); + TEST_ASSERT_EQUAL_HEX16(0x07FF, test2_len_16); + + esp_efuse_utility_debug_dump_blocks(); +} + +TEST_CASE("efuse test write_field_cnt", "[efuse]") +{ + test_write_cnt(); +} + +void cut_tail_arr(uint8_t *arr, int num_used_bits, size_t count_bits) +{ + if ((num_used_bits + count_bits) % 8) { + int start_used_item = (num_used_bits - 1) / 8; + int last_used_item = ((num_used_bits + count_bits) - 1) / 8; + int shift = 0; + int mask = num_used_bits + count_bits; + if (last_used_item == start_used_item) { + shift = (num_used_bits) % 8; + mask = count_bits; + } + arr[last_used_item] &= ((1 << (mask % 8)) - 1) << shift; + } +} + +void cut_start_arr(uint8_t *arr, size_t num_used_bits) +{ + if (num_used_bits % 8) { + int start_used_item = (num_used_bits - 1) / 8; + arr[start_used_item] &= ~((1 << (num_used_bits % 8)) - 1); + } +} + +void get_part_arr(uint8_t *arr_in, uint8_t *arr_out, int num_used_bits, int count_bits) +{ + int num_items = esp_efuse_utility_get_number_of_items(num_used_bits + count_bits, 8); + memcpy(arr_out, arr_in, num_items); + memset(arr_out, 0, num_used_bits / 8); + cut_start_arr(arr_out, num_used_bits); + cut_tail_arr(arr_out, num_used_bits, count_bits); +} + +void fill_part_arr(uint8_t *arr_in, uint8_t *arr_out, int count_bits) +{ + int num_items = esp_efuse_utility_get_number_of_items(count_bits, 8); + memcpy(arr_out, arr_in, num_items); + cut_tail_arr(arr_out, 0, count_bits); +} + +// Writes a random array to efuse, then reads and compares it. +void test_blob(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size) +{ + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO); + TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_w, field_size)); + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO); + esp_efuse_utility_debug_dump_blocks(); + + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_w, arr_r, arr_size) == 0, "Operation write/read blob is not success"); + + int count_once = 0; + for (int i = 0; i < arr_size; ++i) { + count_once += __builtin_popcount(arr_w[i]); + } + + size_t num_bits_r = 0; + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(count_once, num_bits_r); + + size_t num_bits_w = field_size - count_once; + if (num_bits_w == 0) { + esp_efuse_utility_erase_virt_blocks(); + num_bits_w = field_size; + } + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_INT(field_size, num_bits_r); + + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + memset(arr_temp, 0xFF, arr_size); + cut_tail_arr(arr_temp, 0, field_size); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success"); +} + +// Records a random number of bits (as "1") in the efuse field, then reads and compares. +void test_cnt_part(const esp_efuse_desc_t* field[], uint8_t *arr_r, int arr_size, size_t field_size) +{ + size_t num_bits_r = 0; + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(0, num_bits_r); + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, field_size)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + TEST_ASSERT_EQUAL_INT(field_size, num_bits_r); + + esp_efuse_utility_erase_virt_blocks(); + + int num_bits_summ_r = 0; + int num_bits_w = 0; + while(field_size > num_bits_summ_r) { + num_bits_w = 0; + while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) { + bootloader_random_enable(); + bootloader_fill_random(&num_bits_w, 1); + bootloader_random_disable(); + num_bits_w = num_bits_w * field_size / 255; + if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) { + break; + } + } + + TEST_ESP_OK(esp_efuse_write_field_cnt(field, num_bits_w)); + TEST_ESP_OK(esp_efuse_read_field_cnt(field, &num_bits_r)); + num_bits_summ_r += num_bits_w; + TEST_ASSERT_EQUAL_INT(num_bits_summ_r, num_bits_r); + + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + int count_once = 0; + for (int i = 0; i < arr_size; ++i) { + count_once += __builtin_popcount(arr_r[i]); + } + TEST_ASSERT_EQUAL_INT(num_bits_summ_r, count_once); + + ESP_LOGI(TAG, "Once bits=%d, step=%d", num_bits_summ_r, num_bits_w); + } + + esp_efuse_utility_debug_dump_blocks(); +} + +// From a random array takes a random number of bits and write to efuse, it repeats until the entire length of the field is written down. +void test_blob_part(const esp_efuse_desc_t* field[], uint8_t *arr_w, uint8_t *arr_r, uint8_t *arr_temp, int arr_size, size_t field_size) +{ + esp_efuse_utility_debug_dump_blocks(); + int num_bits_summ_r = 0; + int num_bits_w = 0; + memset(arr_w, 0, arr_size); + bootloader_random_enable(); + bootloader_fill_random(arr_w, arr_size); + bootloader_random_disable(); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_w, arr_size, ESP_LOG_INFO); + while(field_size > num_bits_summ_r) { + num_bits_w = 0; + while(num_bits_w == 0 || (num_bits_summ_r + num_bits_w) > field_size) { + bootloader_random_enable(); + bootloader_fill_random(&num_bits_w, 1); + bootloader_random_disable(); + num_bits_w = num_bits_w * field_size / 255; + if (num_bits_w != 0 && (num_bits_summ_r + num_bits_w) <= field_size) { + break; + } + } + ESP_LOGI(TAG, "Summ bits=%d, step=%d", num_bits_summ_r, num_bits_w); + memset(arr_temp, 0, arr_size); + get_part_arr(arr_w, arr_temp, num_bits_summ_r, num_bits_w); + + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO); + TEST_ESP_OK(esp_efuse_write_field_blob(field, arr_temp, field_size)); + memset(arr_r, 0, arr_size); + TEST_ESP_OK(esp_efuse_read_field_blob(field, arr_r, field_size)); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_r, arr_size, ESP_LOG_INFO); + esp_efuse_utility_debug_dump_blocks(); + + num_bits_summ_r += num_bits_w; + memset(arr_temp, 0, arr_size); + fill_part_arr(arr_w, arr_temp, num_bits_summ_r); + ESP_LOG_BUFFER_HEX_LEVEL(TAG, arr_temp, arr_size, ESP_LOG_INFO); + TEST_ASSERT_TRUE_MESSAGE(memcmp(arr_temp, arr_r, arr_size) == 0, "Operation write/read blob is not success"); + } +} + +void check_efuse_table_test(int cycle) +{ + int num_test = 0; + while(1) { + const esp_efuse_desc_t** field; + switch (num_test++) { + case 0: field = ESP_EFUSE_TEST1_LEN_8; break; + case 1: field = ESP_EFUSE_TEST2_LEN_16; break; + case 2: field = ESP_EFUSE_TEST3_LEN_6; break; + case 3: field = ESP_EFUSE_TEST4_LEN_182; break; + case 4: field = ESP_EFUSE_TEST5_LEN_1; break; + case 5: field = ESP_EFUSE_TEST6_LEN_17; break; + default: + return; + break; + } + size_t field_size = esp_efuse_get_field_size(field); + int arr_size = esp_efuse_utility_get_number_of_items(field_size, 8); + uint8_t *arr_w = (uint8_t *) malloc(arr_size); + uint8_t *arr_r = (uint8_t *) malloc(arr_size); + uint8_t *arr_temp = (uint8_t *) malloc(arr_size); + ESP_LOGI(TAG, "Test#%d", num_test); + for (int c = 1; c <= cycle; ++c) { + ESP_LOGI(TAG, "Cycle#%d/%d", c, cycle); + + memset(arr_w, 0, arr_size); + bootloader_random_enable(); + bootloader_fill_random(arr_w, arr_size); + bootloader_random_disable(); + cut_tail_arr(arr_w, 0, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "1) blob write/read"); + test_blob(field, arr_w, arr_r, arr_temp, arr_size, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "2) cnt part write/read"); + test_cnt_part(field, arr_r, arr_size, field_size); + + esp_efuse_utility_erase_virt_blocks(); + ESP_LOGI(TAG, "3) blob part write/read"); + test_blob_part(field, arr_w, arr_r, arr_temp, arr_size, field_size); + } + free(arr_temp); + free(arr_r); + free(arr_w); + } +} + +TEST_CASE("efuse esp_efuse_table_test", "[efuse]") +{ + check_efuse_table_test(2); +} + + +TEST_CASE("Test esp_efuse_read_block esp_efuse_write_block functions", "[efuse]") +{ + int count_useful_reg = 0; + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + + esp_efuse_utility_reset(); + esp_efuse_utility_erase_virt_blocks(); + + uint8_t src_key[32] = { 0 }; + uint8_t dst_key[32] = { 0 }; + int offset_in_bits = 0; + for (int i = 0; i < count_useful_reg * 4; ++i) { + src_key[i] = 0xAB + i; + } + + TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32)); + TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, sizeof(src_key)); + + esp_efuse_utility_erase_virt_blocks(); + + memset(src_key, 0, sizeof(src_key)); + memset(dst_key, 0, sizeof(dst_key)); + offset_in_bits = count_useful_reg * 32 / 2; + for (int i = 0; i < count_useful_reg * 4 / 2; ++i) { + src_key[i] = 0xCD + i; + } + TEST_ESP_OK(esp_efuse_write_block(EFUSE_BLK2, src_key, offset_in_bits, count_useful_reg * 32 / 2)); + TEST_ESP_OK(esp_efuse_read_block(EFUSE_BLK2, dst_key, offset_in_bits, count_useful_reg * 32 / 2)); + esp_efuse_utility_debug_dump_blocks(); + TEST_ASSERT_EQUAL_HEX8_ARRAY(src_key, dst_key, count_useful_reg * 4 / 2); + + esp_efuse_utility_erase_virt_blocks(); +} + +TEST_CASE("Test Bits are not empty. Write operation is forbidden", "[efuse]") +{ + esp_efuse_utility_update_virt_blocks(); + esp_efuse_utility_debug_dump_blocks(); + + int count_useful_reg = 0; + uint8_t r_buff[32]; + int st_offset = -1; + int num_block; + for (num_block = EFUSE_BLK1; num_block < 4; ++num_block) { + memset(r_buff, 0, sizeof(r_buff)); + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(num_block); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE. The test is not applicable.\n"); + count_useful_reg = 8; + return; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + TEST_ESP_OK(esp_efuse_read_block(num_block, r_buff, 0, count_useful_reg * 32)); + for (int i = 0; i < count_useful_reg * 4; ++i) { + if (r_buff[i] != 0) { + // found used byte + for (int j = 0; j < 8; ++j) { + if ((r_buff[i] & (1 << j)) == 0) { + // found empty bit into this byte + st_offset = i * 8 + j; + printf("Byte = 0x%02x. offset is = %d\n", r_buff[i], st_offset); + break; + } + } + if (st_offset != -1) { + break; + } + } + } + if (st_offset != -1) { + break; + } + } + if (st_offset != -1) { + // write 1 bit to empty place. + uint8_t val = 1; + TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_write_block(num_block, &val, st_offset, 1)); + } else { + printf("Test skipped. It is not applicable, the device has no written bits."); + } +} +#endif // #ifdef CONFIG_EFUSE_VIRTUAL diff --git a/components/efuse/test/test_efuse_coding_scheme.c b/components/efuse/test/test_efuse_coding_scheme.c new file mode 100644 index 000000000..242702d9f --- /dev/null +++ b/components/efuse/test/test_efuse_coding_scheme.c @@ -0,0 +1,204 @@ +#include +#include +#include "esp_efuse.h" +#include "../src/esp_efuse_utility.h" +#include "soc/efuse_reg.h" +#include "unity.h" +#include "bootloader_random.h" + +typedef struct { + uint8_t unencoded[24]; + uint32_t encoded[8]; +} coding_scheme_test_t; + +/* Randomly generated byte strings, encoded and written to ESP32 + using espefuse algorithm, then verified to have no encoding errors + and correct readback. +*/ +static const coding_scheme_test_t coding_scheme_data[] = { + { + .unencoded = { 0x96, 0xa9, 0xab, 0xb2, 0xda, 0xdd, 0x21, 0xd2, 0x35, 0x22, 0xd3, 0x30, 0x3b, 0xf8, 0xcb, 0x77, 0x8d, 0x8d, 0xf4, 0x96, 0x25, 0xc4, 0xb9, 0x94 }, + .encoded = { 0xb2aba996, 0x6821ddda, 0x2235d221, 0x430730d3, 0x77cbf83b, 0x627f8d8d, 0xc42596f4, 0x4dae94b9 }, + }, + { + .unencoded = { 0x0e, 0x6b, 0x1a, 0x1d, 0xa5, 0x9f, 0x24, 0xcf, 0x91, 0x5b, 0xe7, 0xe1, 0x7c, 0x0a, 0x6e, 0xdc, 0x5e, 0x8e, 0xb1, 0xec, 0xd1, 0xf3, 0x75, 0x48 }, + .encoded = { 0x1d1a6b0e, 0x5e589fa5, 0x5b91cf24, 0x6127e1e7, 0xdc6e0a7c, 0x5d148e5e, 0xf3d1ecb1, 0x57424875 }, + }, + { + .unencoded = { 0x0a, 0x79, 0x5a, 0x1c, 0xb1, 0x45, 0x71, 0x2c, 0xb3, 0xda, 0x9e, 0xdc, 0x76, 0x27, 0xf5, 0xca, 0xe7, 0x00, 0x39, 0x95, 0x6c, 0x53, 0xc2, 0x07 }, + .encoded = { 0x1c5a790a, 0x4ac145b1, 0xdab32c71, 0x6476dc9e, 0xcaf52776, 0x4d8900e7, 0x536c9539, 0x495607c2 }, + }, + { + .unencoded = { 0x76, 0x46, 0x88, 0x2d, 0x4c, 0xe1, 0x50, 0x5d, 0xd6, 0x7c, 0x41, 0x15, 0xc6, 0x1f, 0xd4, 0x60, 0x10, 0x15, 0x2a, 0x72, 0x2d, 0x89, 0x93, 0x13 }, + .encoded = { 0x2d884676, 0x4838e14c, 0x7cd65d50, 0x4bf31541, 0x60d41fc6, 0x39681510, 0x892d722a, 0x497c1393 }, + }, + { + .unencoded = { 0x32, 0xbc, 0x40, 0x92, 0x13, 0x37, 0x1a, 0xae, 0xb6, 0x00, 0xed, 0x30, 0xb8, 0x82, 0xee, 0xfc, 0xcf, 0x6d, 0x7f, 0xc5, 0xfa, 0x0e, 0xdd, 0x84 }, + .encoded = { 0x9240bc32, 0x49783713, 0x00b6ae1a, 0x46df30ed, 0xfcee82b8, 0x6e8a6dcf, 0x0efac57f, 0x571784dd }, + }, + { + .unencoded = { 0x29, 0xb3, 0x04, 0x95, 0xf2, 0x3c, 0x81, 0xe6, 0x5a, 0xf3, 0x42, 0x82, 0xd1, 0x79, 0xe2, 0x12, 0xbe, 0xc3, 0xd4, 0x10, 0x63, 0x66, 0x9f, 0xe3 }, + .encoded = { 0x9504b329, 0x51c53cf2, 0xf35ae681, 0x460e8242, 0x12e279d1, 0x5825c3be, 0x666310d4, 0x5ebde39f }, + }, + { + .unencoded = { 0xda, 0xda, 0x71, 0x4a, 0x62, 0x33, 0xdd, 0x31, 0x87, 0xf3, 0x70, 0x12, 0x33, 0x3b, 0x3b, 0xe9, 0xed, 0xc4, 0x6e, 0x6a, 0xc7, 0xd5, 0x85, 0xfc }, + .encoded = { 0x4a71dada, 0x4e6a3362, 0xf38731dd, 0x4bfa1270, 0xe93b3b33, 0x61f3c4ed, 0xd5c76a6e, 0x636ffc85 }, + }, + { + .unencoded = { 0x45, 0x64, 0x51, 0x34, 0x1c, 0x82, 0x81, 0x77, 0xf8, 0x89, 0xb1, 0x15, 0x82, 0x94, 0xdd, 0x64, 0xa2, 0x46, 0x0e, 0xfb, 0x1a, 0x70, 0x4b, 0x9f }, + .encoded = { 0x34516445, 0x39da821c, 0x89f87781, 0x4f2315b1, 0x64dd9482, 0x474b46a2, 0x701afb0e, 0x5e4b9f4b }, + }, + { + .unencoded = { 0x89, 0x87, 0x15, 0xb6, 0x66, 0x34, 0x49, 0x18, 0x8b, 0x7b, 0xb2, 0xf6, 0x96, 0x1e, 0x2e, 0xf1, 0x03, 0x9d, 0x4e, 0x16, 0x32, 0xd6, 0x23, 0x22 }, + .encoded = { 0xb6158789, 0x4eff3466, 0x7b8b1849, 0x63e5f6b2, 0xf12e1e96, 0x54c99d03, 0xd632164e, 0x42bd2223 }, + }, + { + .unencoded = { 0xa7, 0xa0, 0xb5, 0x21, 0xd2, 0xa3, 0x9f, 0x65, 0xa9, 0xeb, 0x72, 0xa2, 0x2e, 0xa6, 0xfb, 0x9c, 0x48, 0x7e, 0x68, 0x08, 0x7a, 0xb1, 0x4f, 0xbc }, + .encoded = { 0x21b5a0a7, 0x4ce2a3d2, 0xeba9659f, 0x5868a272, 0x9cfba62e, 0x5fd97e48, 0xb17a0868, 0x5b58bc4f }, + }, + { + .unencoded = { 0xf7, 0x05, 0xe3, 0x6c, 0xb1, 0x55, 0xcb, 0x2f, 0x8d, 0x3e, 0x0b, 0x2e, 0x3e, 0xb7, 0x02, 0xf5, 0x91, 0xb1, 0xfe, 0x8b, 0x58, 0x50, 0xb2, 0x40 }, + .encoded = { 0x6ce305f7, 0x569955b1, 0x3e8d2fcb, 0x56722e0b, 0xf502b73e, 0x535eb191, 0x50588bfe, 0x3a8f40b2 }, + }, + { + .unencoded = { 0x0f, 0x93, 0xb0, 0xd5, 0x60, 0xba, 0x40, 0x2a, 0x62, 0xa6, 0x92, 0x82, 0xb8, 0x91, 0x2c, 0xd7, 0x23, 0xdc, 0x6f, 0x7f, 0x2f, 0xbe, 0x41, 0xf5 }, + .encoded = { 0xd5b0930f, 0x5123ba60, 0xa6622a40, 0x3bbe8292, 0xd72c91b8, 0x582ddc23, 0xbe2f7f6f, 0x6935f541 }, + }, + { + .unencoded = { 0x7f, 0x0c, 0x99, 0xde, 0xff, 0x2e, 0xd2, 0x1c, 0x48, 0x98, 0x70, 0x85, 0x15, 0x01, 0x2a, 0xfb, 0xcd, 0xf2, 0xa0, 0xf9, 0x0e, 0xbc, 0x9f, 0x0c }, + .encoded = { 0xde990c7f, 0x6fe52eff, 0x98481cd2, 0x3deb8570, 0xfb2a0115, 0x61faf2cd, 0xbc0ef9a0, 0x55780c9f }, + }, + { + .unencoded = { 0x9a, 0x10, 0x92, 0x03, 0x81, 0xfe, 0x41, 0x57, 0x77, 0x02, 0xcb, 0x20, 0x67, 0xa4, 0x97, 0xf3, 0xf8, 0xc7, 0x0d, 0x65, 0xcd, 0xfc, 0x15, 0xef }, + .encoded = { 0x0392109a, 0x4b64fe81, 0x02775741, 0x418820cb, 0xf397a467, 0x6998c7f8, 0xfccd650d, 0x6ba3ef15 }, + }, +}; + +TEST_CASE("Test 3/4 Coding Scheme Algorithm", "[efuse]") +{ + const int num_tests = sizeof(coding_scheme_data)/sizeof(coding_scheme_test_t); + for (int i = 0; i < num_tests; i++) { + uint32_t result[8]; + const coding_scheme_test_t *t = &coding_scheme_data[i]; + + printf("Test case %d...\n", i); + esp_err_t r = esp_efuse_apply_34_encoding(t->unencoded, result, sizeof(t->unencoded)); + TEST_ASSERT_EQUAL_HEX(ESP_OK, r); + TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded, result, 8); + + // Do the same, 6 bytes at a time + for (int offs = 0; offs < sizeof(t->unencoded); offs += 6) { + bzero(result, sizeof(result)); + r = esp_efuse_apply_34_encoding(t->unencoded + offs, result, 6); + TEST_ASSERT_EQUAL_HEX(ESP_OK, r); + TEST_ASSERT_EQUAL_HEX32_ARRAY(t->encoded + (offs / 6 * 2), result, 2); + } + } +} + +TEST_CASE("Test Coding Scheme for efuse manager", "[efuse]") +{ + int count_useful_reg = 0; + int useful_data_in_byte; + uint8_t buf[32]; + uint32_t encoded[8]; + bootloader_random_enable(); + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4; + } + useful_data_in_byte = count_useful_reg * 4; + + for (int i = 0; i < 10; ++i) { + printf("Test case %d...\n", i); + memset(buf, 0, sizeof(buf)); + memset(encoded, 0, sizeof(encoded)); + // get test data + bootloader_fill_random(buf, useful_data_in_byte); + memset(buf, 0, i); + + esp_efuse_utility_reset(); + + for (int j = 0; j < count_useful_reg; ++j) { + REG_WRITE(EFUSE_BLK2_WDATA0_REG + j * 4, *((uint32_t*)buf + j)); + } + + TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme()); + + uint32_t w_data_after_coding[8] = { 0 }; + for (int j = 0; j < 8; ++j) { + w_data_after_coding[j] = REG_READ(EFUSE_BLK2_WDATA0_REG + j * 4); + } + + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + memcpy((uint8_t*)encoded, buf, sizeof(buf)); + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + TEST_ESP_OK(esp_efuse_apply_34_encoding(buf, encoded, useful_data_in_byte)); + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + for (int j = 0; j < count_useful_reg; ++j) { + encoded[j] = *((uint32_t*)buf + j); + encoded[j + 4] = encoded[j]; + } + } +#ifdef CONFIG_EFUSE_VIRTUAL + printf("Data from W reg\n"); + esp_efuse_utility_erase_virt_blocks(); + esp_efuse_utility_burn_efuses(); + esp_efuse_utility_debug_dump_blocks(); + printf("Data from encoded\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", encoded[j]); + } + printf("\nData from w_data_after_coding\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", w_data_after_coding[j]); + } + + printf("\nData from buf\n"); + for (int j = 0; j < 8; ++j) { + printf("0x%08x ", *((uint32_t*)buf + j)); + } + printf("\n"); +#endif + TEST_ASSERT_EQUAL_HEX32_ARRAY(encoded, w_data_after_coding, 8); + } + esp_efuse_utility_reset(); + bootloader_random_disable(); +} + +TEST_CASE("Test data does not match the coding scheme", "[efuse]") +{ + int count_useful_reg = 0; + esp_efuse_coding_scheme_t coding_scheme = esp_efuse_get_coding_scheme(EFUSE_BLK2); + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + printf("EFUSE_CODING_SCHEME_NONE\n"); + count_useful_reg = 8; + } else if (coding_scheme == EFUSE_CODING_SCHEME_3_4) { + printf("EFUSE_CODING_SCHEME_3_4\n"); + count_useful_reg = 6 + 1; + } else if (coding_scheme == EFUSE_CODING_SCHEME_REPEAT) { + printf("EFUSE_CODING_SCHEME_REPEAT\n"); + count_useful_reg = 4 + 1; + } + + esp_efuse_utility_reset(); + + for (int i = 0; i < count_useful_reg; ++i) { + REG_WRITE(EFUSE_BLK2_WDATA0_REG + i * 4, 0xABCDEF01 + i); + } + + if (coding_scheme == EFUSE_CODING_SCHEME_NONE) { + TEST_ESP_OK(esp_efuse_utility_apply_new_coding_scheme()); + } else { + TEST_ESP_ERR(ESP_ERR_CODING, esp_efuse_utility_apply_new_coding_scheme()); + } + + esp_efuse_utility_reset(); +} diff --git a/components/efuse/test_efuse_host/efuse_tests.py b/components/efuse/test_efuse_host/efuse_tests.py new file mode 100644 index 000000000..e2a546b94 --- /dev/null +++ b/components/efuse/test_efuse_host/efuse_tests.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python +from __future__ import print_function, division +import unittest +import struct +import csv +import sys +import subprocess +import tempfile +import os +import StringIO +sys.path.append("..") +from efuse import * + +''' +To run the test on local PC: +cd ~/esp/esp-idf/components/efuse/test_efuse_host/ + ./efuse_tests.py +''' + + +class CSVParserTests(unittest.TestCase): + + def test_general(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + self.assertEqual(t[0].comment, 'Use for test name 1') + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + self.assertEqual(t[1].comment, 'Use for test name 2') + + def test_seq_bit_start1_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK3, , 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + + def test_seq_bit_start2_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + def test_seq_bit_start3_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, + +name3, EFUSE_BLK2, 5, 4, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name3') + self.assertEqual(t[2].bit_start, 5) + self.assertEqual(t[2].bit_count, 4) + + def test_seq_bit_start4_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +, EFUSE_BLK2, , 4, +name1, EFUSE_BLK3, , 5, +""" + with self.assertRaisesRegexp(InputError, "Field names must be unique"): + t = FuseTable.from_csv(csv) + + + def test_seq_bit_start5_fill(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +, EFUSE_BLK2, , 4, +name3, EFUSE_BLK3, 5, 5, +""" + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].bit_start, 0) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name2') + self.assertEqual(t[2].bit_start, 4) + self.assertEqual(t[2].bit_count, 4) + + self.assertEqual(t[3].field_name, 'name3') + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 5) + + def test_overlapping_bit_start_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 1, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "overlap"): + t.verify() + + def test_empty_field_name_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +, EFUSE_BLK3, , 5, +name2, EFUSE_BLK2, , 4, +""" + with self.assertRaisesRegexp(InputError, "missing field name"): + t = FuseTable.from_csv(csv) + + def test_unique_field_name_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name1, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "Field names must be unique"): + t = FuseTable.from_csv(csv) + + def test_bit_count_empty_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, , Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "empty"): + t = FuseTable.from_csv(csv) + + def test_bit_start_num_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, k, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "Invalid field value"): + t = FuseTable.from_csv(csv) + + def test_join_entry(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK2, 0, 6, Use for test name 1 +name2, EFUSE_BLK2, 6, 5, Use for test name 2 +name3, EFUSE_BLK3, 20, 5, Use for test name 3 +, EFUSE_BLK3, 30, 5, Use for test name 3 +name4, EFUSE_BLK2, 30, 5, Use for test name 4 + """ + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 6) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[1].bit_start, 6) + self.assertEqual(t[1].bit_count, 5) + + self.assertEqual(t[2].field_name, 'name3') + self.assertEqual(t[2].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[2].bit_start, 20) + self.assertEqual(t[2].bit_count, 5) + + self.assertEqual(t[3].field_name, 'name3') + self.assertEqual(t[3].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[3].bit_start, 30) + self.assertEqual(t[3].bit_count, 5) + + self.assertEqual(t[4].field_name, 'name4') + self.assertEqual(t[4].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[4].bit_start, 30) + self.assertEqual(t[4].bit_count, 5) + + def test_block_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK5, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 + """ + with self.assertRaisesRegexp(InputError, "'efuse_block' should consist from EFUSE_BLK0..EFUSE_BLK3"): + t = FuseTable.from_csv(csv) + + def test_field_size_is_ok(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 0, 224, Use for test name 1 +name2, EFUSE_BLK1, 0, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + t.verify() + + def test_field_blk0_size_is_more(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 1, 224, Use for test name 1 +name2, EFUSE_BLK1, 0, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + t.verify() + + def test_field_blk1_size_is_more(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK0, 0, 224, Use for test name 1 +name2, EFUSE_BLK1, 1, 256, Use for test name 2 + """ + t = FuseTable.from_csv(csv) + with self.assertRaisesRegexp(InputError, "The field is outside the boundaries"): + t.verify() + +class VerificationTests(unittest.TestCase): + + def test_bit_start_num_fail(self): + csv = """ +# field_name, efuse_block(EFUSE_BLK0..EFUSE_BLK3), bit_start(0..255), bit_count, comment +name1, EFUSE_BLK3, 0, 5, Use for test name 1 +name2, EFUSE_BLK3, 5, 4, Use for test name 2 +name1_1, EFUSE_BLK2, 0, 5, Use for test name 1_1 +name2_1, EFUSE_BLK2, 5, 4, Use for test name 2_1 + """ + t = FuseTable.from_csv(csv) + t.verify() + + self.assertEqual(t[0].field_name, 'name1') + self.assertEqual(t[0].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[0].bit_start, 0) + self.assertEqual(t[0].bit_count, 5) + + self.assertEqual(t[1].field_name, 'name2') + self.assertEqual(t[1].efuse_block, 'EFUSE_BLK3') + self.assertEqual(t[1].bit_start, 5) + self.assertEqual(t[1].bit_count, 4) + + self.assertEqual(t[2].field_name, 'name1_1') + self.assertEqual(t[2].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[2].bit_start, 0) + self.assertEqual(t[2].bit_count, 5) + + self.assertEqual(t[3].field_name, 'name2_1') + self.assertEqual(t[3].efuse_block, 'EFUSE_BLK2') + self.assertEqual(t[3].bit_start, 5) + self.assertEqual(t[3].bit_count, 4) + +if __name__ =="__main__": + unittest.main()