1# This file describes eFuses controller 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
7import time
8
9from .mem_definition import EfuseDefineBlocks, EfuseDefineFields, EfuseDefineRegisters
10from ..emulate_efuse_controller_base import EmulateEfuseControllerBase, FatalError
11
12
13class EmulateEfuseController(EmulateEfuseControllerBase):
14    """The class for virtual efuse operations. Using for HOST_TEST."""
15
16    CHIP_NAME = "ESP32"
17    mem = None
18    debug = False
19
20    def __init__(self, efuse_file=None, debug=False):
21        self.Blocks = EfuseDefineBlocks
22        self.Fields = EfuseDefineFields(None)
23        self.REGS = EfuseDefineRegisters
24        super(EmulateEfuseController, self).__init__(efuse_file, debug)
25
26    """ esptool method start >> """
27
28    def get_major_chip_version(self):
29        return 3
30
31    def get_minor_chip_version(self):
32        return 0
33
34    def get_crystal_freq(self):
35        return 40  # MHz (common for all chips)
36
37    def read_reg(self, addr):
38        if addr == self.REGS.APB_CTL_DATE_ADDR:
39            return self.REGS.APB_CTL_DATE_V << self.REGS.APB_CTL_DATE_S
40        else:
41            return super(EmulateEfuseController, self).read_reg(addr)
42
43    """ << esptool method end """
44
45    def send_burn_cmd(self):
46        def wait_idle():
47            deadline = time.time() + self.REGS.EFUSE_BURN_TIMEOUT
48            while time.time() < deadline:
49                if self.read_reg(self.REGS.EFUSE_REG_CMD) == 0:
50                    return
51            raise FatalError(
52                "Timed out waiting for Efuse controller command to complete"
53            )
54
55        self.write_reg(self.REGS.EFUSE_REG_CMD, self.REGS.EFUSE_CMD_WRITE)
56        wait_idle()
57        self.write_reg(self.REGS.EFUSE_REG_CONF, self.REGS.EFUSE_CONF_READ)
58        self.write_reg(self.REGS.EFUSE_REG_CMD, self.REGS.EFUSE_CMD_READ)
59        wait_idle()
60
61    def handle_writing_event(self, addr, value):
62        if addr == self.REGS.EFUSE_REG_CMD:
63            if value == self.REGS.EFUSE_CMD_WRITE:
64                self.write_reg(addr, 0)
65            elif value == self.REGS.EFUSE_CMD_READ:
66                self.copy_blocks_wr_regs_to_rd_regs()
67                self.clean_blocks_wr_regs()
68                self.check_rd_protection_area()
69                self.write_reg(addr, 0)
70                self.save_to_file()
71
72    def read_raw_coding_scheme(self):
73        coding_scheme = (
74            self.read_efuse(self.REGS.EFUSE_CODING_SCHEME_WORD)
75            & self.REGS.EFUSE_CODING_SCHEME_MASK
76        )
77        if coding_scheme == self.REGS.CODING_SCHEME_NONE_RECOVERY:
78            return self.REGS.CODING_SCHEME_NONE
79        else:
80            return coding_scheme
81
82    def write_raw_coding_scheme(self, value):
83        self.write_efuse(
84            self.REGS.EFUSE_CODING_SCHEME_WORD,
85            value & self.REGS.EFUSE_CODING_SCHEME_MASK,
86        )
87        self.send_burn_cmd()
88        if value != self.read_raw_coding_scheme():
89            raise FatalError(
90                "Error during a burning process to set the new coding scheme"
91            )
92        print("Set coding scheme = %d" % self.read_raw_coding_scheme())
93
94    def get_bitlen_of_block(self, blk, wr=False):
95        if blk.id == 0:
96            return 32 * blk.len
97        else:
98            coding_scheme = self.read_raw_coding_scheme()
99            if coding_scheme == self.REGS.CODING_SCHEME_NONE:
100                return 32 * blk.len
101            elif coding_scheme == self.REGS.CODING_SCHEME_34:
102                if wr:
103                    return 32 * 8
104                else:
105                    return 32 * blk.len * 3 // 4
106            else:
107                raise FatalError(
108                    "The {} coding scheme is not supported".format(coding_scheme)
109                )
110
111    def handle_coding_scheme(self, blk, data):
112        # it verifies the coding scheme part of data and returns just data
113        if blk.id != 0 and self.read_raw_coding_scheme() == self.REGS.CODING_SCHEME_34:
114            # CODING_SCHEME 3/4 applied only for BLK1..3
115            # Takes 24 byte sequence to be represented in 3/4 encoding,
116            # returns 8 words suitable for writing "encoded" to an efuse block
117            data.pos = 0
118            for _ in range(0, 4):
119                xor_res = 0
120                mul_res = 0
121                chunk_data = data.readlist("8*uint:8")
122                chunk_data = chunk_data[::-1]
123                for i in range(0, 6):
124                    byte_data = chunk_data[i]
125                    xor_res ^= byte_data
126                    mul_res += (i + 1) * bin(byte_data).count("1")
127                if xor_res != chunk_data[6] or mul_res != chunk_data[7]:
128                    print(
129                        "xor_res ",
130                        xor_res,
131                        chunk_data[6],
132                        "mul_res",
133                        mul_res,
134                        chunk_data[7],
135                    )
136                    raise FatalError("Error in coding scheme data")
137            # cut the coded data
138            for i in range(0, 4):
139                del data[i * 6 * 8 : (i * 6 * 8) + 16]
140        return data
141