1# This file describes eFuses fields and registers for ESP32 chip 2# 3# SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD 4# 5# SPDX-License-Identifier: GPL-2.0-or-later 6 7from collections import Counter, namedtuple 8import esptool 9from typing import Optional, List 10 11from .csv_table_parser import CSVFuseTable 12 13 14class EfuseRegistersBase(object): 15 # Coding Scheme values 16 CODING_SCHEME_NONE = 0 17 CODING_SCHEME_34 = 1 18 CODING_SCHEME_REPEAT = 2 19 CODING_SCHEME_NONE_RECOVERY = 3 20 CODING_SCHEME_RS = 4 21 22 EFUSE_BURN_TIMEOUT = 0.250 # seconds 23 24 25class EfuseBlocksBase(object): 26 BLOCKS: Optional[List] = None 27 NamedtupleBlock = namedtuple( 28 "NamedtupleBlock", 29 "name alias id rd_addr wr_addr write_disable_bit " 30 "read_disable_bit len key_purpose", 31 ) 32 33 @staticmethod 34 def get(tuple_block): 35 return EfuseBlocksBase.NamedtupleBlock._make(tuple_block) 36 37 def get_blocks_for_keys(self): 38 list_of_names = [] 39 for block in self.BLOCKS: 40 blk = self.get(block) 41 if blk.id > 0: 42 if blk.name: 43 list_of_names.append(blk.name) 44 if blk.alias: 45 for alias in blk.alias: 46 list_of_names.append(alias) 47 return list_of_names 48 49 50class Field: 51 name = "" 52 block = 0 53 word = None 54 pos = None 55 bit_len = 0 56 alt_names: List[str] = [] 57 type = "" 58 write_disable_bit = None 59 read_disable_bit = None 60 category = "config" 61 class_type = "" 62 description = "" 63 dictionary = None 64 65 66class EfuseFieldsBase(object): 67 def __init__(self, e_desc, extend_efuse_table_file) -> None: 68 self.ALL_EFUSES: List = [] 69 70 def set_category_and_class_type(efuse, name): 71 def includes(name, names): 72 return any([word in name for word in names]) 73 74 if name.startswith("SPI_PAD_CONFIG"): 75 efuse.category = "spi pad" 76 77 elif "USB" in name: 78 efuse.category = "usb" 79 80 elif "WDT" in name: 81 efuse.category = "wdt" 82 83 elif "JTAG" in name: 84 efuse.category = "jtag" 85 86 elif includes(name, ["FLASH", "FORCE_SEND_RESUME"]): 87 efuse.category = "flash" 88 89 elif includes(name, ["VDD_SPI_", "XPD"]): 90 efuse.category = "vdd" 91 92 elif "MAC" in name: 93 efuse.category = "MAC" 94 if name in ["MAC", "CUSTOM_MAC", "MAC_EXT"]: 95 efuse.class_type = "mac" 96 97 elif includes( 98 name, 99 [ 100 "BLOCK_KEY0", 101 "BLOCK_KEY1", 102 "BLOCK_KEY2", 103 "BLOCK_KEY3", 104 "BLOCK_KEY4", 105 "BLOCK_KEY5", 106 "BLOCK1", 107 "BLOCK2", 108 ], 109 ): 110 efuse.category = "security" 111 efuse.class_type = "keyblock" 112 113 elif includes( 114 name, 115 [ 116 "KEY", 117 "SECURE", 118 "DOWNLOAD", 119 "SPI_BOOT_CRYPT_CNT", 120 "KEY_PURPOSE", 121 "SECURE_VERSION", 122 "DPA", 123 "ECDSA", 124 "FLASH_CRYPT_CNT", 125 "ENCRYPT", 126 "DECRYPT", 127 "ABS_DONE", 128 ], 129 ): 130 efuse.category = "security" 131 if name.startswith("KEY_PURPOSE"): 132 efuse.class_type = "keypurpose" 133 elif includes( 134 name, ["FLASH_CRYPT_CNT", "SPI_BOOT_CRYPT_CNT", "SECURE_VERSION"] 135 ): 136 efuse.class_type = "bitcount" 137 138 elif includes(name, ["VERSION", "WAFER", "_ID", "PKG", "PACKAGE", "REV"]): 139 efuse.category = "identity" 140 if name == "OPTIONAL_UNIQUE_ID": 141 efuse.class_type = "keyblock" 142 143 elif includes(name, ["ADC", "LDO", "DBIAS", "_HVT", "CALIB", "OCODE"]): 144 efuse.category = "calibration" 145 if name == "ADC_VREF": 146 efuse.class_type = "vref" 147 return 148 if includes(name, ["ADC", "LDO", "DBIAS", "_HVT"]): 149 efuse.class_type = "adc_tp" 150 elif name == "TEMP_CALIB": 151 efuse.class_type = "t_sensor" 152 153 for e_name in e_desc["EFUSES"]: 154 data_dict = e_desc["EFUSES"][e_name] 155 if data_dict["show"] == "y": 156 d = Field() 157 d.name = e_name 158 d.block = data_dict["blk"] 159 d.word = data_dict["word"] 160 d.pos = data_dict["pos"] 161 d.bit_len = data_dict["len"] 162 d.type = data_dict["type"] 163 d.write_disable_bit = data_dict["wr_dis"] 164 d.read_disable_bit = ( 165 [int(x) for x in data_dict["rd_dis"].split(" ")] 166 if isinstance(data_dict["rd_dis"], str) 167 else data_dict["rd_dis"] 168 ) 169 d.description = data_dict["desc"] 170 d.alt_names = data_dict["alt"].split(" ") if data_dict["alt"] else [] 171 d.dictionary = ( 172 eval(data_dict["dict"]) if data_dict["dict"] != "" else None 173 ) 174 set_category_and_class_type(d, e_name) 175 self.ALL_EFUSES.append(d) 176 177 if self.extend_efuses(extend_efuse_table_file): 178 self.check_name_duplicates() 179 180 def check_name_duplicates(self): 181 names = [n.name for n in self.ALL_EFUSES] 182 for n in self.ALL_EFUSES: 183 if n.alt_names: 184 names.extend(n.alt_names) 185 186 name_counts = Counter(names) 187 duplicates = {name for name, count in name_counts.items() if count > 1} 188 if duplicates: 189 print("Names that are not unique: " + ", ".join(duplicates)) 190 raise esptool.FatalError("Duplicate names found in eFuses") 191 192 def extend_efuses(self, extend_efuse_table_file): 193 if extend_efuse_table_file: 194 table = CSVFuseTable.from_csv(extend_efuse_table_file.read()) 195 for p in table: 196 item = Field() 197 item.name = p.field_name 198 item.block = p.efuse_block 199 item.word = p.bit_start // 32 200 item.pos = p.bit_start % 32 201 item.bit_len = p.bit_count 202 if p.bit_count == 1: 203 str_type = "bool" 204 else: 205 if p.bit_count > 32 and p.bit_count % 8 == 0: 206 str_type = f"bytes:{p.bit_count // 8}" 207 else: 208 str_type = f"uint:{p.bit_count}" 209 item.type = str_type 210 item.write_disable_bit = None 211 item.read_disable_bit = None 212 if item.block != 0: 213 # look for an already configured field associated with this field 214 # to take the WR_DIS and RID_DIS bits 215 for field in self.ALL_EFUSES: 216 if field.block == item.block: 217 if field.write_disable_bit is not None: 218 item.write_disable_bit = field.write_disable_bit 219 if field.read_disable_bit is not None: 220 item.read_disable_bit = field.read_disable_bit 221 if ( 222 item.read_disable_bit is not None 223 and item.write_disable_bit is not None 224 ): 225 break 226 item.category = "User" 227 item.description = p.comment 228 item.alt_names = p.alt_names.split(" ") if p.alt_names else [] 229 item.dictionary = "" 230 self.ALL_EFUSES.append(item) 231 return True 232 return False 233